"Fossies" - the Fresh Open Source Software Archive

Member "cutter-1.10.3/src/core/Cutter.cpp" (8 May 2020, 106506 Bytes) of package /linux/privat/cutter-1.10.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "Cutter.cpp" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.10.2_vs_1.10.3.

    1 #include <QJsonArray>
    2 #include <QJsonObject>
    3 #include <QRegularExpression>
    4 #include <QDir>
    5 #include <QCoreApplication>
    6 #include <QVector>
    7 #include <QStringList>
    8 #include <QStandardPaths>
    9 
   10 #include <cassert>
   11 #include <memory>
   12 
   13 #include "common/TempConfig.h"
   14 #include "common/BasicInstructionHighlighter.h"
   15 #include "common/Configuration.h"
   16 #include "common/AsyncTask.h"
   17 #include "common/R2Task.h"
   18 #include "common/Json.h"
   19 #include "core/Cutter.h"
   20 #include "Decompiler.h"
   21 #include "r_asm.h"
   22 #include "r_cmd.h"
   23 #include "sdb.h"
   24 
   25 Q_GLOBAL_STATIC(CutterCore, uniqueInstance)
   26 
   27 #define R_JSON_KEY(name) static const QString name = QStringLiteral(#name)
   28 
   29 namespace RJsonKey {
   30     R_JSON_KEY(addr);
   31     R_JSON_KEY(addr_end);
   32     R_JSON_KEY(arrow);
   33     R_JSON_KEY(baddr);
   34     R_JSON_KEY(bind);
   35     R_JSON_KEY(blocks);
   36     R_JSON_KEY(blocksize);
   37     R_JSON_KEY(bytes);
   38     R_JSON_KEY(calltype);
   39     R_JSON_KEY(cc);
   40     R_JSON_KEY(classname);
   41     R_JSON_KEY(code);
   42     R_JSON_KEY(comment);
   43     R_JSON_KEY(comments);
   44     R_JSON_KEY(cost);
   45     R_JSON_KEY(data);
   46     R_JSON_KEY(description);
   47     R_JSON_KEY(ebbs);
   48     R_JSON_KEY(edges);
   49     R_JSON_KEY(enabled);
   50     R_JSON_KEY(entropy);
   51     R_JSON_KEY(fcn_addr);
   52     R_JSON_KEY(fcn_name);
   53     R_JSON_KEY(fields);
   54     R_JSON_KEY(file);
   55     R_JSON_KEY(flags);
   56     R_JSON_KEY(flagname);
   57     R_JSON_KEY(format);
   58     R_JSON_KEY(from);
   59     R_JSON_KEY(functions);
   60     R_JSON_KEY(graph);
   61     R_JSON_KEY(haddr);
   62     R_JSON_KEY(hw);
   63     R_JSON_KEY(in_functions);
   64     R_JSON_KEY(index);
   65     R_JSON_KEY(jump);
   66     R_JSON_KEY(laddr);
   67     R_JSON_KEY(lang);
   68     R_JSON_KEY(len);
   69     R_JSON_KEY(length);
   70     R_JSON_KEY(license);
   71     R_JSON_KEY(methods);
   72     R_JSON_KEY(name);
   73     R_JSON_KEY(realname);
   74     R_JSON_KEY(nargs);
   75     R_JSON_KEY(nbbs);
   76     R_JSON_KEY(nlocals);
   77     R_JSON_KEY(offset);
   78     R_JSON_KEY(opcode);
   79     R_JSON_KEY(opcodes);
   80     R_JSON_KEY(ordinal);
   81     R_JSON_KEY(libname);
   82     R_JSON_KEY(outdegree);
   83     R_JSON_KEY(paddr);
   84     R_JSON_KEY(path);
   85     R_JSON_KEY(perm);
   86     R_JSON_KEY(pid);
   87     R_JSON_KEY(plt);
   88     R_JSON_KEY(prot);
   89     R_JSON_KEY(ref);
   90     R_JSON_KEY(refs);
   91     R_JSON_KEY(reg);
   92     R_JSON_KEY(rwx);
   93     R_JSON_KEY(section);
   94     R_JSON_KEY(sections);
   95     R_JSON_KEY(size);
   96     R_JSON_KEY(stackframe);
   97     R_JSON_KEY(status);
   98     R_JSON_KEY(string);
   99     R_JSON_KEY(strings);
  100     R_JSON_KEY(symbols);
  101     R_JSON_KEY(text);
  102     R_JSON_KEY(to);
  103     R_JSON_KEY(trace);
  104     R_JSON_KEY(type);
  105     R_JSON_KEY(uid);
  106     R_JSON_KEY(vaddr);
  107     R_JSON_KEY(value);
  108     R_JSON_KEY(vsize);
  109 }
  110 
  111 #undef R_JSON_KEY
  112 
  113 static void updateOwnedCharPtr(char *&variable, const QString &newValue)
  114 {
  115     auto data = newValue.toUtf8();
  116     R_FREE(variable)
  117     variable = strdup(data.data());
  118 }
  119 
  120 static QString fromOwnedCharPtr(char *str) {
  121     QString result(str ? str : "");
  122     r_mem_free(str);
  123     return result;
  124 }
  125 
  126 RCoreLocked::RCoreLocked(CutterCore *core)
  127     : core(core)
  128 {
  129     core->coreMutex.lock();
  130     assert(core->coreLockDepth >= 0);
  131     core->coreLockDepth++;
  132     if (core->coreLockDepth == 1) {
  133         assert(core->coreBed);
  134         r_cons_sleep_end(core->coreBed);
  135         core->coreBed = nullptr;
  136     }
  137 }
  138 
  139 RCoreLocked::~RCoreLocked()
  140 {
  141     assert(core->coreLockDepth > 0);
  142     core->coreLockDepth--;
  143     if (core->coreLockDepth == 0) {
  144         core->coreBed = r_cons_sleep_begin();
  145     }
  146     core->coreMutex.unlock();
  147 }
  148 
  149 RCoreLocked::operator RCore *() const
  150 {
  151     return core->core_;
  152 }
  153 
  154 RCore *RCoreLocked::operator->() const
  155 {
  156     return core->core_;
  157 }
  158 
  159 #define CORE_LOCK() RCoreLocked core(this)
  160 
  161 static void cutterREventCallback(REvent *, int type, void *user, void *data)
  162 {
  163     auto core = reinterpret_cast<CutterCore *>(user);
  164     core->handleREvent(type, data);
  165 }
  166 
  167 CutterCore::CutterCore(QObject *parent) :
  168     QObject(parent), coreMutex(QMutex::Recursive)
  169 {
  170 }
  171 
  172 CutterCore *CutterCore::instance()
  173 {
  174     return uniqueInstance;
  175 }
  176 
  177 void CutterCore::initialize(bool loadPlugins)
  178 {
  179     r_cons_new();  // initialize console
  180     core_ = r_core_new();
  181     r_core_task_sync_begin(&core_->tasks);
  182     coreBed = r_cons_sleep_begin();
  183     CORE_LOCK();
  184 
  185     r_event_hook(core_->anal->ev, R_EVENT_ALL, cutterREventCallback, this);
  186 
  187 #if defined(APPIMAGE) || defined(MACOS_R2_BUNDLED)
  188     auto prefix = QDir(QCoreApplication::applicationDirPath());
  189 #ifdef APPIMAGE
  190     // Executable is in appdir/bin
  191     prefix.cdUp();
  192     qInfo() << "Setting r2 prefix =" << prefix.absolutePath() << " for AppImage.";
  193 #else // MACOS_R2_BUNDLED
  194     // Executable is in Contents/MacOS, prefix is Contents/Resources/r2
  195     prefix.cdUp();
  196     prefix.cd("Resources");
  197     prefix.cd("r2");
  198     qInfo() << "Setting r2 prefix =" << prefix.absolutePath() << " for macOS Application Bundle.";
  199 #endif
  200     setConfig("dir.prefix", prefix.absolutePath());
  201 
  202     auto pluginsDir = prefix;
  203     if (pluginsDir.cd("share/radare2/plugins")) {
  204         qInfo() << "Setting r2 plugins dir =" << pluginsDir.absolutePath();
  205         setConfig("dir.plugins", pluginsDir.absolutePath());
  206     } else {
  207         qInfo() << "r2 plugins dir =" << pluginsDir.absolutePath() << "does not exist!";
  208     }
  209 #endif
  210 
  211     if (!loadPlugins) {
  212         setConfig("cfg.plugins", 0);
  213     }
  214     if (getConfigi("cfg.plugins")) {
  215         r_core_loadlibs(this->core_, R_CORE_LOADLIBS_ALL, nullptr);
  216     }
  217     // IMPLICIT r_bin_iobind (core_->bin, core_->io);
  218 
  219     // Otherwise r2 may ask the user for input and Cutter would freeze
  220     setConfig("scr.interactive", false);
  221 
  222     // Initialize graph node highlighter
  223     bbHighlighter = new BasicBlockHighlighter();
  224 
  225     // Initialize Async tasks manager
  226     asyncTaskManager = new AsyncTaskManager(this);
  227 }
  228 
  229 CutterCore::~CutterCore()
  230 {
  231     delete bbHighlighter;
  232     r_cons_sleep_end(coreBed);
  233     r_core_task_sync_end(&core_->tasks);
  234     r_core_free(this->core_);
  235     r_cons_free();
  236 }
  237 
  238 RCoreLocked CutterCore::core()
  239 {
  240     return RCoreLocked(this);
  241 }
  242 
  243 QVector<QDir> CutterCore::getCutterRCDirectories() const
  244 {
  245     QVector<QDir> result;
  246     result.push_back(QDir::home());
  247     QStringList locations = QStandardPaths::standardLocations(QStandardPaths::AppConfigLocation);
  248     for (auto &location : locations) { 
  249         result.push_back(QDir(location)); 
  250     }
  251     return result;
  252 }
  253 
  254 void CutterCore::loadCutterRC()
  255 {
  256     CORE_LOCK();
  257     
  258     const auto result = getCutterRCDirectories();
  259     for(auto &dir : result){
  260         if(!dir.exists())continue;
  261         auto cutterRCFileInfo = QFileInfo(dir, ".cutterrc");
  262         auto path = cutterRCFileInfo.absoluteFilePath();
  263         if (!cutterRCFileInfo.isFile()) {
  264             continue;
  265         }
  266         qInfo() << "Loading initialization file from" << path;
  267         r_core_cmd_file(core, path.toUtf8().constData());
  268     }
  269 }
  270 
  271 
  272 QList<QString> CutterCore::sdbList(QString path)
  273 {
  274     CORE_LOCK();
  275     QList<QString> list = QList<QString>();
  276     Sdb *root = sdb_ns_path(core->sdb, path.toUtf8().constData(), 0);
  277     if (root) {
  278         void *vsi;
  279         ls_iter_t *iter;
  280         ls_foreach(root->ns, iter, vsi) {
  281             SdbNs *nsi = (SdbNs *)vsi;
  282             list << nsi->name;
  283         }
  284     }
  285     return list;
  286 }
  287 
  288 using SdbListPtr = std::unique_ptr<SdbList, decltype (&ls_free)>;
  289 static SdbListPtr makeSdbListPtr(SdbList *list)
  290 {
  291     return {list, ls_free};
  292 }
  293 
  294 QList<QString> CutterCore::sdbListKeys(QString path)
  295 {
  296     CORE_LOCK();
  297     QList<QString> list = QList<QString>();
  298     Sdb *root = sdb_ns_path(core->sdb, path.toUtf8().constData(), 0);
  299     if (root) {
  300         void *vsi;
  301         ls_iter_t *iter;
  302         SdbListPtr l = makeSdbListPtr(sdb_foreach_list(root, false));
  303         ls_foreach(l, iter, vsi) {
  304             SdbKv *nsi = (SdbKv *)vsi;
  305             list << reinterpret_cast<char *>(nsi->base.key);
  306         }
  307     }
  308     return list;
  309 }
  310 
  311 QString CutterCore::sdbGet(QString path, QString key)
  312 {
  313     CORE_LOCK();
  314     Sdb *db = sdb_ns_path(core->sdb, path.toUtf8().constData(), 0);
  315     if (db) {
  316         const char *val = sdb_const_get(db, key.toUtf8().constData(), 0);
  317         if (val && *val)
  318             return val;
  319     }
  320     return QString();
  321 }
  322 
  323 bool CutterCore::sdbSet(QString path, QString key, QString val)
  324 {
  325     CORE_LOCK();
  326     Sdb *db = sdb_ns_path(core->sdb, path.toUtf8().constData(), 1);
  327     if (!db) return false;
  328     return sdb_set(db, key.toUtf8().constData(), val.toUtf8().constData(), 0);
  329 }
  330 
  331 QString CutterCore::sanitizeStringForCommand(QString s)
  332 {
  333     static const QRegularExpression regexp(";|@");
  334     return s.replace(regexp, QStringLiteral("_"));
  335 }
  336 
  337 QString CutterCore::cmd(const char *str)
  338 {
  339     CORE_LOCK();
  340 
  341     RVA offset = core->offset;
  342     char *res = r_core_cmd_str(core, str);
  343     QString o = fromOwnedCharPtr(res);
  344 
  345     if (offset != core->offset) {
  346         updateSeek();
  347     }
  348     return o;
  349 }
  350 
  351 bool CutterCore::isRedirectableDebugee()
  352 {
  353     if (!currentlyDebugging || currentlyAttachedToPID != -1) {
  354         return false;
  355     }
  356 
  357     // We are only able to redirect locally debugged unix processes
  358     QJsonArray openFilesArray = cmdj("oj").array();;
  359     for (QJsonValue value : openFilesArray) {
  360         QJsonObject openFile = value.toObject();
  361         QString URI = openFile["uri"].toString();
  362         if (URI.contains("ptrace") | URI.contains("mach")) {
  363             return true;
  364         }
  365     }
  366     return false;
  367 }
  368 
  369 bool CutterCore::isDebugTaskInProgress()
  370 {
  371     if (!debugTask.isNull()) {
  372         return true;
  373     }
  374 
  375     return false;
  376 }
  377 
  378 bool CutterCore::asyncCmdEsil(const char *command, QSharedPointer<R2Task> &task)
  379 {
  380     asyncCmd(command, task);
  381 
  382     if (task.isNull()) {
  383         return false;
  384     }
  385 
  386     connect(task.data(), &R2Task::finished, task.data(), [this, task] () {
  387         QString res = task.data()->getResult();
  388 
  389         if (res.contains(QStringLiteral("[ESIL] Stopped execution in an invalid instruction"))) {
  390             msgBox.showMessage("Stopped when attempted to run an invalid instruction. You can disable this in Preferences");
  391         }
  392     });
  393 
  394     return true;
  395 }
  396 
  397 bool CutterCore::asyncCmd(const char *str, QSharedPointer<R2Task> &task)
  398 {
  399     if (!task.isNull()) {
  400         return false;
  401     }
  402 
  403     CORE_LOCK();
  404 
  405     RVA offset = core->offset;
  406 
  407     task = QSharedPointer<R2Task>(new R2Task(str, true));
  408     connect(task.data(), &R2Task::finished, task.data(), [this, offset, task] () {
  409         CORE_LOCK();
  410 
  411         if (offset != core->offset) {
  412             updateSeek();
  413         }
  414     });
  415 
  416     return true;
  417 }
  418 
  419 QString CutterCore::cmdRawAt(const char *cmd, RVA address)
  420 {
  421     QString res;
  422     RVA oldOffset = getOffset();
  423     seekSilent(address);
  424 
  425     res = cmdRaw(cmd);
  426 
  427     seekSilent(oldOffset);
  428     return res;
  429 }
  430 
  431 QString CutterCore::cmdRaw(const char *cmd)
  432 {
  433     QString res;
  434     CORE_LOCK();
  435     r_cons_push ();
  436 
  437     // r_cmd_call does not return the output of the command
  438     r_cmd_call(core->rcmd, cmd);
  439 
  440     // we grab the output straight from r_cons
  441     res = r_cons_get_buffer();
  442 
  443     // cleaning up
  444     r_cons_pop ();
  445     r_cons_echo (NULL);
  446     
  447     return res;
  448 }
  449 
  450 QJsonDocument CutterCore::cmdj(const char *str)
  451 {
  452     char *res;
  453     {
  454         CORE_LOCK();
  455         res = r_core_cmd_str(core, str);
  456     }
  457 
  458     QJsonDocument doc = parseJson(res, str);
  459     r_mem_free(res);
  460 
  461     return doc;
  462 }
  463 
  464 QString CutterCore::cmdTask(const QString &str)
  465 {
  466     R2Task task(str);
  467     task.startTask();
  468     task.joinTask();
  469     return task.getResult();
  470 }
  471 
  472 QJsonDocument CutterCore::cmdjTask(const QString &str)
  473 {
  474     R2Task task(str);
  475     task.startTask();
  476     task.joinTask();
  477     return parseJson(task.getResultRaw(), str);
  478 }
  479 
  480 QJsonDocument CutterCore::parseJson(const char *res, const char *cmd)
  481 {
  482     QByteArray json(res);
  483 
  484     if (json.isEmpty()) {
  485         return QJsonDocument();
  486     }
  487 
  488     QJsonParseError jsonError;
  489     QJsonDocument doc = QJsonDocument::fromJson(json, &jsonError);
  490 
  491     if (jsonError.error != QJsonParseError::NoError) {
  492         if (cmd) {
  493             eprintf("Failed to parse JSON for command \"%s\": %s\n", cmd,
  494                     jsonError.errorString().toLocal8Bit().constData());
  495         } else {
  496             eprintf("Failed to parse JSON: %s\n", jsonError.errorString().toLocal8Bit().constData());
  497         }
  498         const int MAX_JSON_DUMP_SIZE = 8 * 1024;
  499         if (json.length() > MAX_JSON_DUMP_SIZE) {
  500             int originalSize = json.length();
  501             json.resize(MAX_JSON_DUMP_SIZE);
  502             eprintf("%d bytes total: %s ...\n", originalSize, json.constData());
  503         } else {
  504             eprintf("%s\n", json.constData());
  505         }
  506     }
  507 
  508     return doc;
  509 }
  510 
  511 QStringList CutterCore::autocomplete(const QString &cmd, RLinePromptType promptType, size_t limit)
  512 {
  513     RLineBuffer buf;
  514     int c = snprintf(buf.data, sizeof(buf.data), "%s", cmd.toUtf8().constData());
  515     if (c < 0) {
  516         return {};
  517     }
  518     buf.index = buf.length = std::min((int)(sizeof(buf.data) - 1), c);
  519 
  520     RLineCompletion completion;
  521     r_line_completion_init(&completion, limit);
  522     r_core_autocomplete(core(), &completion, &buf, promptType);
  523 
  524     QStringList r;
  525     r.reserve(r_pvector_len(&completion.args));
  526     for (size_t i = 0; i < r_pvector_len(&completion.args); i++) {
  527         r.push_back(QString::fromUtf8(reinterpret_cast<const char *>(r_pvector_at(&completion.args, i))));
  528     }
  529 
  530     r_line_completion_fini(&completion);
  531     return r;
  532 }
  533 
  534 /**
  535  * @brief CutterCore::loadFile
  536  * Load initial file. TODO Maybe use the "o" commands?
  537  * @param path File path
  538  * @param baddr Base (RBin) address
  539  * @param mapaddr Map address
  540  * @param perms
  541  * @param va
  542  * @param loadbin Load RBin information
  543  * @param forceBinPlugin
  544  * @return
  545  */
  546 bool CutterCore::loadFile(QString path, ut64 baddr, ut64 mapaddr, int perms, int va,
  547                           bool loadbin, const QString &forceBinPlugin)
  548 {
  549     CORE_LOCK();
  550     RCoreFile *f;
  551     r_config_set_i(core->config, "io.va", va);
  552 
  553     f = r_core_file_open(core, path.toUtf8().constData(), perms, mapaddr);
  554     if (!f) {
  555         eprintf("r_core_file_open failed\n");
  556         return false;
  557     }
  558 
  559     if (!forceBinPlugin.isNull()) {
  560         r_bin_force_plugin(r_core_get_bin(core), forceBinPlugin.toUtf8().constData());
  561     }
  562 
  563     if (loadbin && va) {
  564         if (!r_core_bin_load(core, path.toUtf8().constData(), baddr)) {
  565             eprintf("CANNOT GET RBIN INFO\n");
  566         }
  567 
  568 #if HAVE_MULTIPLE_RBIN_FILES_INSIDE_SELECT_WHICH_ONE
  569         if (!r_core_file_open(core, path.toUtf8(), R_IO_READ | (rw ? R_IO_WRITE : 0, mapaddr))) {
  570             eprintf("Cannot open file\n");
  571         } else {
  572             // load RBin information
  573             // XXX only for sub-bins
  574             r_core_bin_load(core, path.toUtf8(), baddr);
  575             r_bin_select_idx(core->bin, NULL, idx);
  576         }
  577 #endif
  578     } else {
  579         // Not loading RBin info coz va = false
  580     }
  581 
  582     auto iod = core->io ? core->io->desc : NULL;
  583     auto debug = core->file && iod && (core->file->fd == iod->fd) && iod->plugin && \
  584                  iod->plugin->isdbg;
  585 
  586     if (!debug && r_flag_get (core->flags, "entry0")) {
  587         r_core_cmd0 (core, "s entry0");
  588     }
  589 
  590     if (perms & R_PERM_W) {
  591         r_core_cmd0 (core, "omfg+w");
  592     }
  593 
  594     ut64 hashLimit = getConfigut64("cfg.hashlimit");
  595     r_bin_file_compute_hashes(core->bin, hashLimit);
  596 
  597     fflush(stdout);
  598     return true;
  599 }
  600 
  601 bool CutterCore::tryFile(QString path, bool rw)
  602 {
  603     CORE_LOCK();
  604     RCoreFile *cf;
  605     int flags = R_PERM_R;
  606     if (rw) flags = R_PERM_RW;
  607     cf = r_core_file_open(core, path.toUtf8().constData(), flags, 0LL);
  608     if (!cf) {
  609         return false;
  610     }
  611 
  612     r_core_file_close (core, cf);
  613 
  614     return true;
  615 }
  616 
  617 /**
  618  * @brief Maps a file using r2 API
  619  * @param path Path to file
  620  * @param mapaddr Map Address
  621  * @return bool
  622  */
  623 bool CutterCore::mapFile(QString path, RVA mapaddr)
  624 {
  625     CORE_LOCK();
  626     RVA addr = mapaddr != RVA_INVALID ? mapaddr : 0;
  627     ut64 baddr = Core()->getFileInfo().object()["bin"].toObject()["baddr"].toVariant().toULongLong();
  628     if (r_core_file_open(core, path.toUtf8().constData(), R_PERM_RX, addr)) {
  629         r_core_bin_load(core, path.toUtf8().constData(), baddr);
  630     } else {
  631         return false;
  632     }
  633     return true;
  634 }
  635 
  636 void CutterCore::renameFunction(const QString &oldName, const QString &newName)
  637 {
  638     cmdRaw("afn " + newName + " " + oldName);
  639     emit functionRenamed(oldName, newName);
  640 }
  641 
  642 void CutterCore::delFunction(RVA addr)
  643 {
  644     cmdRaw("af- " + RAddressString(addr));
  645     emit functionsChanged();
  646 }
  647 
  648 void CutterCore::renameFlag(QString old_name, QString new_name)
  649 {
  650     cmdRaw("fr " + old_name + " " + new_name);
  651     emit flagsChanged();
  652 }
  653 
  654 void CutterCore::delFlag(RVA addr)
  655 {
  656     cmdRawAt("f-", addr);
  657     emit flagsChanged();
  658 }
  659 
  660 void CutterCore::delFlag(const QString &name)
  661 {
  662     cmdRaw("f-" + name);
  663     emit flagsChanged();
  664 }
  665 
  666 QString CutterCore::getInstructionBytes(RVA addr)
  667 {
  668     return cmdj("aoj @ " + RAddressString(addr)).array().first().toObject()[RJsonKey::bytes].toString();
  669 }
  670 
  671 QString CutterCore::getInstructionOpcode(RVA addr)
  672 {
  673     return cmdj("aoj @ " + RAddressString(addr)).array().first().toObject()[RJsonKey::opcode].toString();
  674 }
  675 
  676 void CutterCore::editInstruction(RVA addr, const QString &inst)
  677 {
  678     cmdRawAt(QString("wa %1").arg(inst), addr);
  679     emit instructionChanged(addr);
  680 }
  681 
  682 void CutterCore::nopInstruction(RVA addr)
  683 {
  684     cmdRawAt("wao nop", addr);
  685     emit instructionChanged(addr);
  686 }
  687 
  688 void CutterCore::jmpReverse(RVA addr)
  689 {
  690     cmdRawAt("wao recj", addr);
  691     emit instructionChanged(addr);
  692 }
  693 
  694 void CutterCore::editBytes(RVA addr, const QString &bytes)
  695 {
  696     cmdRawAt(QString("wx %1").arg(bytes), addr);
  697     emit instructionChanged(addr);
  698 }
  699 
  700 void CutterCore::editBytesEndian(RVA addr, const QString &bytes)
  701 {
  702     cmdRawAt(QString("wv %1").arg(bytes), addr);
  703     emit stackChanged();
  704 }
  705 
  706 void CutterCore::setToCode(RVA addr)
  707 {
  708     cmdRawAt("Cd-", addr);
  709     emit instructionChanged(addr);
  710 }
  711 
  712 void CutterCore::setAsString(RVA addr, int size, StringTypeFormats type)
  713 {
  714     if(RVA_INVALID == addr)
  715     {
  716         return;
  717     }
  718 
  719     QString command;
  720 
  721     switch(type)
  722     {
  723     case StringTypeFormats::None:
  724     {
  725         command = "Cs";
  726         break;
  727     }
  728     case StringTypeFormats::ASCII_LATIN1:
  729     {
  730         command = "Csa";
  731         break;
  732     }
  733     case StringTypeFormats::UTF8:
  734     {
  735         command = "Cs8";
  736         break;
  737     }
  738     default:
  739         return;
  740     }
  741 
  742     seekAndShow(addr);
  743 
  744     cmdRawAt(QString("%1 %2").arg(command).arg(size), addr);
  745     emit instructionChanged(addr);
  746 }
  747 
  748 void CutterCore::removeString(RVA addr)
  749 {
  750     cmdRawAt("Cs-", addr);
  751     emit instructionChanged(addr);
  752 }
  753 
  754 QString CutterCore::getString(RVA addr)
  755 {
  756     return cmdRawAt("ps", addr);
  757 }
  758 
  759 void CutterCore::setToData(RVA addr, int size, int repeat)
  760 {
  761     if (size <= 0 || repeat <= 0) {
  762         return;
  763     }
  764     cmdRawAt("Cd-", addr);
  765     cmdRawAt(QString("Cd %1 %2").arg(size).arg(repeat), addr);
  766     emit instructionChanged(addr);
  767 }
  768 
  769 int CutterCore::sizeofDataMeta(RVA addr)
  770 {
  771     bool ok;
  772     int size = cmdRawAt("Cd.", addr).toInt(&ok);
  773     return (ok ? size : 0);
  774 }
  775 
  776 void CutterCore::setComment(RVA addr, const QString &cmt)
  777 {
  778     cmdRawAt(QString("CCu base64:%1").arg(QString(cmt.toLocal8Bit().toBase64())), addr);
  779     emit commentsChanged();
  780 }
  781 
  782 void CutterCore::delComment(RVA addr)
  783 {
  784     cmdRawAt("CC-", addr);
  785     emit commentsChanged();
  786 }
  787 
  788 /**
  789  * @brief Gets the comment present at a specific address
  790  * @param addr The address to be checked
  791  * @return String containing comment
  792  */
  793 QString CutterCore::getCommentAt(RVA addr)
  794 {
  795     CORE_LOCK();
  796     return fromOwnedCharPtr(r_meta_get_string(core->anal, R_META_TYPE_COMMENT, addr));
  797 }
  798 
  799 void CutterCore::setImmediateBase(const QString &r2BaseName, RVA offset)
  800 {
  801     if (offset == RVA_INVALID) {
  802         offset = getOffset();
  803     }
  804 
  805     this->cmdRawAt(QString("ahi %1").arg(r2BaseName), offset);
  806     emit instructionChanged(offset);
  807 }
  808 
  809 void CutterCore::setCurrentBits(int bits, RVA offset)
  810 {
  811     if (offset == RVA_INVALID) {
  812         offset = getOffset();
  813     }
  814 
  815     this->cmdRawAt(QString("ahb %1").arg(bits), offset);
  816     emit instructionChanged(offset);
  817 }
  818 
  819 void CutterCore::applyStructureOffset(const QString &structureOffset, RVA offset)
  820 {
  821     if (offset == RVA_INVALID) {
  822         offset = getOffset();
  823     }
  824 
  825     this->cmdRawAt("aht " + structureOffset, offset);
  826     emit instructionChanged(offset);
  827 }
  828 
  829 void CutterCore::seekSilent(ut64 offset)
  830 {
  831     CORE_LOCK();
  832     if (offset == RVA_INVALID) {
  833         return;
  834     }
  835     r_core_seek(core, offset, true);
  836 }
  837 
  838 void CutterCore::seek(ut64 offset)
  839 {
  840     // Slower than using the API, but the API is not complete
  841     // which means we either have to duplicate code from radare2
  842     // here, or refactor radare2 API.
  843     CORE_LOCK();
  844     if (offset == RVA_INVALID) {
  845         return;
  846     }
  847 
  848     // use cmd and not cmdRaw to make sure seekChanged is emitted
  849     cmd(QString("s %1").arg(offset));
  850     // cmd already does emit seekChanged(core_->offset);
  851 }
  852 
  853 void CutterCore::showMemoryWidget()
  854 {
  855     emit showMemoryWidgetRequested();
  856 }
  857 
  858 void CutterCore::seekAndShow(ut64 offset)
  859 {
  860     seek(offset);
  861     showMemoryWidget();
  862 }
  863 
  864 void CutterCore::seekAndShow(QString offset)
  865 {
  866     seek(offset);
  867     showMemoryWidget();
  868 }
  869 
  870 void CutterCore::seek(QString thing)
  871 {
  872     cmdRaw(QString("s %1").arg(thing));
  873     updateSeek();
  874 }
  875 
  876 void CutterCore::seekPrev()
  877 {
  878     // Use cmd because cmdRaw does not work with seek history
  879     cmd("s-");
  880 }
  881 
  882 void CutterCore::seekNext()
  883 {
  884     // Use cmd because cmdRaw does not work with seek history
  885     cmd("s+");
  886 }
  887 
  888 void CutterCore::updateSeek()
  889 {
  890     emit seekChanged(getOffset());
  891 }
  892 
  893 RVA CutterCore::prevOpAddr(RVA startAddr, int count)
  894 {
  895     CORE_LOCK();
  896     bool ok;
  897     RVA offset = cmdRawAt(QString("/O %1").arg(count), startAddr).toULongLong(&ok, 16);
  898     return ok ? offset : startAddr - count;
  899 }
  900 
  901 RVA CutterCore::nextOpAddr(RVA startAddr, int count)
  902 {
  903     CORE_LOCK();
  904 
  905     QJsonArray array = Core()->cmdj("pdj " + QString::number(count + 1) + "@" + QString::number(
  906                                         startAddr)).array();
  907     if (array.isEmpty()) {
  908         return startAddr + 1;
  909     }
  910 
  911     QJsonValue instValue = array.last();
  912     if (!instValue.isObject()) {
  913         return startAddr + 1;
  914     }
  915 
  916     bool ok;
  917     RVA offset = instValue.toObject()[RJsonKey::offset].toVariant().toULongLong(&ok);
  918     if (!ok) {
  919         return startAddr + 1;
  920     }
  921 
  922     return offset;
  923 }
  924 
  925 RVA CutterCore::getOffset()
  926 {
  927     return core_->offset;
  928 }
  929 
  930 ut64 CutterCore::math(const QString &expr)
  931 {
  932     CORE_LOCK();
  933     return r_num_math(core ? core->num : NULL, expr.toUtf8().constData());
  934 }
  935 
  936 ut64 CutterCore::num(const QString &expr)
  937 {
  938     CORE_LOCK();
  939     return r_num_get(core ? core->num : NULL, expr.toUtf8().constData());
  940 }
  941 
  942 QString CutterCore::itoa(ut64 num, int rdx)
  943 {
  944     return QString::number(num, rdx);
  945 }
  946 
  947 void CutterCore::setConfig(const char *k, const QString &v)
  948 {
  949     CORE_LOCK();
  950     r_config_set(core->config, k, v.toUtf8().constData());
  951 }
  952 
  953 void CutterCore::setConfig(const char *k, int v)
  954 {
  955     CORE_LOCK();
  956     r_config_set_i(core->config, k, static_cast<ut64>(v));
  957 }
  958 
  959 void CutterCore::setConfig(const char *k, bool v)
  960 {
  961     CORE_LOCK();
  962     r_config_set_i(core->config, k, v ? 1 : 0);
  963 }
  964 
  965 int CutterCore::getConfigi(const char *k)
  966 {
  967     CORE_LOCK();
  968     return static_cast<int>(r_config_get_i(core->config, k));
  969 }
  970 
  971 ut64 CutterCore::getConfigut64(const char *k)
  972 {
  973     CORE_LOCK();
  974     return r_config_get_i(core->config, k);
  975 }
  976 
  977 bool CutterCore::getConfigb(const char *k)
  978 {
  979     CORE_LOCK();
  980     return r_config_get_i(core->config, k) != 0;
  981 }
  982 
  983 QString CutterCore::getConfigDescription(const char *k)
  984 {
  985     CORE_LOCK();
  986     RConfigNode *node = r_config_node_get (core->config, k);
  987     return QString(node->desc);
  988 }
  989 
  990 void CutterCore::triggerRefreshAll()
  991 {
  992     emit refreshAll();
  993 }
  994 
  995 void CutterCore::triggerAsmOptionsChanged()
  996 {
  997     emit asmOptionsChanged();
  998 }
  999 
 1000 void CutterCore::triggerGraphOptionsChanged()
 1001 {
 1002     emit graphOptionsChanged();
 1003 }
 1004 
 1005 void CutterCore::message(const QString &msg, bool debug)
 1006 {
 1007     if (msg.isEmpty())
 1008         return;
 1009     if (debug) {
 1010         qDebug() << msg;
 1011         emit newDebugMessage(msg);
 1012         return;
 1013     }
 1014     emit newMessage(msg);
 1015 }
 1016 
 1017 QString CutterCore::getConfig(const char *k)
 1018 {
 1019     CORE_LOCK();
 1020     return QString(r_config_get(core->config, k));
 1021 }
 1022 
 1023 void CutterCore::setConfig(const char *k, const QVariant &v)
 1024 {
 1025     switch (v.type()) {
 1026     case QVariant::Type::Bool:
 1027         setConfig(k, v.toBool());
 1028         break;
 1029     case QVariant::Type::Int:
 1030         setConfig(k, v.toInt());
 1031         break;
 1032     default:
 1033         setConfig(k, v.toString());
 1034         break;
 1035     }
 1036 }
 1037 
 1038 void CutterCore::setCPU(QString arch, QString cpu, int bits)
 1039 {
 1040     if (arch != nullptr) {
 1041         setConfig("asm.arch", arch);
 1042     }
 1043     if (cpu != nullptr) {
 1044         setConfig("asm.cpu", cpu);
 1045     }
 1046     setConfig("asm.bits", bits);
 1047 }
 1048 
 1049 void CutterCore::setEndianness(bool big)
 1050 {
 1051     setConfig("cfg.bigendian", big);
 1052 }
 1053 
 1054 QByteArray CutterCore::assemble(const QString &code)
 1055 {
 1056     CORE_LOCK();
 1057     RAsmCode *ac = r_asm_massemble(core->assembler, code.toUtf8().constData());
 1058     QByteArray res;
 1059     if (ac && ac->bytes) {
 1060         res = QByteArray(reinterpret_cast<const char *>(ac->bytes), ac->len);
 1061     }
 1062     r_asm_code_free(ac);
 1063     return res;
 1064 }
 1065 
 1066 QString CutterCore::disassemble(const QByteArray &data)
 1067 {
 1068     CORE_LOCK();
 1069     RAsmCode *ac = r_asm_mdisassemble(core->assembler, reinterpret_cast<const ut8 *>(data.constData()), data.length());
 1070     QString code;
 1071     if (ac && ac->assembly) {
 1072         code = QString::fromUtf8(ac->assembly);
 1073     }
 1074     r_asm_code_free(ac);
 1075     return code;
 1076 }
 1077 
 1078 QString CutterCore::disassembleSingleInstruction(RVA addr)
 1079 {
 1080     return cmdRawAt("pi 1", addr).simplified();
 1081 }
 1082 
 1083 RAnalFunction *CutterCore::functionIn(ut64 addr)
 1084 {
 1085     CORE_LOCK();
 1086     RList *fcns = r_anal_get_functions_in (core->anal, addr);
 1087     RAnalFunction *fcn = !r_list_empty(fcns) ? reinterpret_cast<RAnalFunction *>(r_list_first(fcns)) : nullptr;
 1088     r_list_free(fcns);
 1089     return fcn;
 1090 }
 1091 
 1092 RAnalFunction *CutterCore::functionAt(ut64 addr)
 1093 {
 1094     CORE_LOCK();
 1095     return r_anal_get_function_at(core->anal, addr);
 1096 }
 1097 
 1098 /**
 1099  * @brief finds the start address of a function in a given address
 1100  * @param addr - an address which belongs to a function
 1101  * @returns if function exists, return its start address. Otherwise return RVA_INVALID
 1102  */
 1103 RVA CutterCore::getFunctionStart(RVA addr)
 1104 {
 1105     CORE_LOCK();
 1106     RAnalFunction *fcn = Core()->functionIn(addr);
 1107     return fcn ? fcn->addr : RVA_INVALID;
 1108 }
 1109 
 1110 /**
 1111  * @brief finds the end address of a function in a given address
 1112  * @param addr - an address which belongs to a function
 1113  * @returns if function exists, return its end address. Otherwise return RVA_INVALID
 1114  */
 1115 RVA CutterCore::getFunctionEnd(RVA addr)
 1116 {
 1117     CORE_LOCK();
 1118     RAnalFunction *fcn = Core()->functionIn(addr);
 1119     return fcn ? fcn->addr : RVA_INVALID;
 1120 }
 1121 
 1122 /**
 1123  * @brief finds the last instruction of a function in a given address
 1124  * @param addr - an address which belongs to a function
 1125  * @returns if function exists, return the address of its last instruction. Otherwise return RVA_INVALID
 1126  */
 1127 RVA CutterCore::getLastFunctionInstruction(RVA addr)
 1128 {
 1129     CORE_LOCK();
 1130     RAnalFunction *fcn = Core()->functionIn(addr);
 1131     if (!fcn) {
 1132         return RVA_INVALID;
 1133     }
 1134     RAnalBlock *lastBB = (RAnalBlock *)r_list_last(fcn->bbs);
 1135     return lastBB ? lastBB->addr + r_anal_bb_offset_inst(lastBB, lastBB->ninstr-1) : RVA_INVALID;
 1136 }
 1137 
 1138 QString CutterCore::cmdFunctionAt(QString addr)
 1139 {
 1140     QString ret;
 1141     // Use cmd because cmdRaw would not work with grep
 1142     ret = cmd(QString("fd @ %1~[0]").arg(addr));
 1143     return ret.trimmed();
 1144 }
 1145 
 1146 QString CutterCore::cmdFunctionAt(RVA addr)
 1147 {
 1148     return cmdFunctionAt(QString::number(addr));
 1149 }
 1150 
 1151 void CutterCore::cmdEsil(const char *command)
 1152 {
 1153     // use cmd and not cmdRaw because of unexpected commands
 1154     QString res = cmd(command);
 1155     if (res.contains(QStringLiteral("[ESIL] Stopped execution in an invalid instruction"))) {
 1156         msgBox.showMessage("Stopped when attempted to run an invalid instruction. You can disable this in Preferences");
 1157     }
 1158 }
 1159 
 1160 QString CutterCore::createFunctionAt(RVA addr)
 1161 {
 1162     QString ret = cmdRaw(QString("af %1").arg(addr));
 1163     emit functionsChanged();
 1164     return ret;
 1165 }
 1166 
 1167 QString CutterCore::createFunctionAt(RVA addr, QString name)
 1168 {
 1169     static const QRegularExpression regExp("[^a-zA-Z0-9_]");
 1170     name.remove(regExp);
 1171     QString ret = cmdRawAt(QString("af %1").arg(name), addr);
 1172     emit functionsChanged();
 1173     return ret;
 1174 }
 1175 
 1176 QJsonDocument CutterCore::getRegistersInfo()
 1177 {
 1178     return cmdj("aeafj");
 1179 }
 1180 
 1181 RVA CutterCore::getOffsetJump(RVA addr)
 1182 {
 1183     bool ok;
 1184     RVA value = cmdj("aoj @" + QString::number(
 1185                          addr)).array().first().toObject().value(RJsonKey::jump).toVariant().toULongLong(&ok);
 1186 
 1187     if (!ok) {
 1188         return RVA_INVALID;
 1189     }
 1190 
 1191     return value;
 1192 }
 1193 
 1194 
 1195 QList<Decompiler *> CutterCore::getDecompilers()
 1196 {
 1197     return decompilers;
 1198 }
 1199 
 1200 Decompiler *CutterCore::getDecompilerById(const QString &id)
 1201 {
 1202     for (Decompiler *dec : decompilers) {
 1203         if (dec->getId() == id) {
 1204             return dec;
 1205         }
 1206     }
 1207     return nullptr;
 1208 }
 1209 
 1210 bool CutterCore::registerDecompiler(Decompiler *decompiler)
 1211 {
 1212     if (getDecompilerById(decompiler->getId())) {
 1213         return false;
 1214     }
 1215     decompiler->setParent(this);
 1216     decompilers.push_back(decompiler);
 1217     return true;
 1218 }
 1219 
 1220 QJsonDocument CutterCore::getFileInfo()
 1221 {
 1222     return cmdj("ij");
 1223 }
 1224 
 1225 QJsonDocument CutterCore::getFileVersionInfo()
 1226 {
 1227     return cmdj("iVj");
 1228 }
 1229 
 1230 QJsonDocument CutterCore::getSignatureInfo()
 1231 {
 1232     return cmdj("iCj");
 1233 }
 1234 
 1235 // Utility function to check if a telescoped item exists and add it with prefixes to the desc
 1236 static inline const QString appendVar(QString &dst, const QString val, const QString prepend_val,
 1237                                        const QString append_val)
 1238 {
 1239     if (!val.isEmpty()) {
 1240         dst += prepend_val + val + append_val;
 1241     }
 1242     return val;
 1243 }
 1244 
 1245 RefDescription CutterCore::formatRefDesc(QJsonObject refItem)
 1246 {
 1247     RefDescription desc;
 1248 
 1249     // Ignore empty refs and refs that only contain addr
 1250     if (refItem.size() <= 1) {
 1251         return desc;
 1252     }
 1253 
 1254     QString str = refItem["string"].toVariant().toString();
 1255     if (!str.isEmpty()) {
 1256         desc.ref = str;
 1257         desc.refColor = ConfigColor("comment");
 1258     } else {
 1259         QString type, string;
 1260         do {
 1261             desc.ref += " ->";
 1262             appendVar(desc.ref, refItem["reg"].toVariant().toString(), " @", "");
 1263             appendVar(desc.ref, refItem["mapname"].toVariant().toString(), " (", ")");
 1264             appendVar(desc.ref, refItem["section"].toVariant().toString(), " (", ")");
 1265             appendVar(desc.ref, refItem["func"].toVariant().toString(), " ", "");
 1266             type = appendVar(desc.ref, refItem["type"].toVariant().toString(), " ", "");
 1267             appendVar(desc.ref, refItem["perms"].toVariant().toString(), " ", "");
 1268             appendVar(desc.ref, refItem["asm"].toVariant().toString(), " \"", "\"");
 1269             string = appendVar(desc.ref, refItem["string"].toVariant().toString(), " ", "");
 1270             if (!string.isNull()) {
 1271                 // There is no point in adding ascii and addr info after a string
 1272                 break;
 1273             }
 1274             if (!refItem["value"].isNull()) {
 1275                 appendVar(desc.ref, RAddressString(refItem["value"].toVariant().toULongLong()), " ", "");
 1276             }
 1277             refItem = refItem["ref"].toObject();
 1278         } while (!refItem.empty());
 1279 
 1280         // Set the ref's color according to the last item type
 1281         if (type == "ascii" || !string.isEmpty()) {
 1282             desc.refColor = ConfigColor("comment");
 1283         } else if (type == "program") {
 1284             desc.refColor = ConfigColor("fname");
 1285         } else if (type == "library") {
 1286             desc.refColor = ConfigColor("floc");
 1287         } else if (type == "stack") {
 1288             desc.refColor = ConfigColor("offset");
 1289         }
 1290     }
 1291 
 1292     return desc;
 1293 }
 1294 
 1295 QList<QJsonObject> CutterCore::getRegisterRefs(int depth)
 1296 {
 1297     QList<QJsonObject> ret;
 1298     if (!currentlyDebugging) {
 1299         return ret;
 1300     }
 1301 
 1302     QJsonObject registers = cmdj("drj").object();
 1303 
 1304     for (const QString &key : registers.keys()) {
 1305         QJsonObject reg;
 1306         reg["value"] = registers.value(key);
 1307         reg["ref"] = getAddrRefs(registers.value(key).toVariant().toULongLong(), depth);
 1308         reg["name"] = key;
 1309         ret.append(reg);
 1310     }
 1311 
 1312     return ret;
 1313 }
 1314 
 1315 QList<QJsonObject> CutterCore::getStack(int size, int depth)
 1316 {
 1317     QList<QJsonObject> stack;
 1318     if (!currentlyDebugging) {
 1319         return stack;
 1320     }
 1321 
 1322     CORE_LOCK();
 1323     bool ret;
 1324     RVA addr = cmdRaw("dr SP").toULongLong(&ret, 16);
 1325     if (!ret) {
 1326         return stack;
 1327     }
 1328 
 1329     int base = core->anal->bits;
 1330     for (int i = 0; i < size; i += base / 8) {
 1331         if ((base == 32 && addr + i >= UT32_MAX) || (base == 16 && addr + i >= UT16_MAX)) {
 1332             break;
 1333         }
 1334 
 1335         stack.append(getAddrRefs(addr + i, depth));
 1336     }
 1337 
 1338     return stack;
 1339 }
 1340 
 1341 QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) {
 1342     QJsonObject json;
 1343     if (depth < 1 || addr == UT64_MAX) {
 1344         return json;
 1345     }
 1346 
 1347     CORE_LOCK();
 1348     int bits = core->assembler->bits;
 1349     QByteArray buf = QByteArray();
 1350     ut64 type = r_core_anal_address(core, addr);
 1351 
 1352     json["addr"] = QString::number(addr);
 1353 
 1354     // Search for the section the addr is in, avoid duplication for heap/stack with type
 1355     if(!(type & R_ANAL_ADDR_TYPE_HEAP || type & R_ANAL_ADDR_TYPE_STACK)) {
 1356         // Attempt to find the address within a map
 1357         RDebugMap *map = r_debug_map_get(core->dbg, addr);
 1358         if (map && map->name && map->name[0]) {
 1359             json["mapname"] = map->name;
 1360         }
 1361 
 1362         RBinSection *sect = r_bin_get_section_at(r_bin_cur_object (core->bin), addr, true);
 1363         if (sect && sect->name[0]) {
 1364             json["section"] = sect->name;
 1365         }
 1366     }
 1367 
 1368     // Check if the address points to a register
 1369     RFlagItem *fi = r_flag_get_i(core->flags, addr);
 1370     if (fi) {
 1371         RRegItem *r = r_reg_get(core->dbg->reg, fi->name, -1);
 1372         if (r) {
 1373             json["reg"] = r->name;
 1374         }
 1375     }
 1376 
 1377     // Attempt to find the address within a function
 1378     RAnalFunction *fcn = r_anal_get_fcn_in(core->anal, addr, 0);
 1379     if (fcn) {
 1380         json["fcn"] = fcn->name;
 1381     }
 1382 
 1383     // Update type and permission information
 1384     if (type != 0) {
 1385         if (type & R_ANAL_ADDR_TYPE_HEAP) {
 1386             json["type"] = "heap";
 1387         } else if (type & R_ANAL_ADDR_TYPE_STACK) {
 1388             json["type"] = "stack";
 1389         } else if (type & R_ANAL_ADDR_TYPE_PROGRAM) {
 1390             json["type"] = "program";
 1391         } else if (type & R_ANAL_ADDR_TYPE_LIBRARY) {
 1392             json["type"] = "library";
 1393         } else if (type & R_ANAL_ADDR_TYPE_ASCII) {
 1394             json["type"] = "ascii";
 1395         } else if (type & R_ANAL_ADDR_TYPE_SEQUENCE) {
 1396             json["type"] = "sequence";
 1397         }
 1398 
 1399         QString perms = "";
 1400         if (type & R_ANAL_ADDR_TYPE_READ) {
 1401             perms += "r";
 1402         }
 1403         if (type & R_ANAL_ADDR_TYPE_WRITE) {
 1404             perms += "w";
 1405         }
 1406         if (type & R_ANAL_ADDR_TYPE_EXEC) {
 1407             RAsmOp op;
 1408             buf.resize(32);
 1409             perms += "x";
 1410             // Instruction disassembly
 1411             r_io_read_at(core->io, addr, (unsigned char*)buf.data(), buf.size());
 1412             r_asm_set_pc(core->assembler, addr);
 1413             r_asm_disassemble(core->assembler, &op, (unsigned char*)buf.data(), buf.size());
 1414             json["asm"] = r_asm_op_get_asm(&op);
 1415         }
 1416 
 1417         if (!perms.isEmpty()) {
 1418             json["perms"] = perms;
 1419         }
 1420     }
 1421 
 1422     // Try to telescope further if depth permits it
 1423     if ((type & R_ANAL_ADDR_TYPE_READ) && !(type & R_ANAL_ADDR_TYPE_EXEC)) {
 1424         buf.resize(64);
 1425         ut32 *n32 = (ut32 *)buf.data();
 1426         ut64 *n64 = (ut64 *)buf.data();
 1427         r_io_read_at(core->io, addr, (unsigned char*)buf.data(), buf.size());
 1428         ut64 n = (bits == 64)? *n64: *n32;
 1429         // The value of the next address will serve as an indication that there's more to
 1430         // telescope if we have reached the depth limit
 1431         json["value"] = QString::number(n);
 1432         if (depth && n != addr) {
 1433             // Make sure we aren't telescoping the same address
 1434             QJsonObject ref = getAddrRefs(n, depth - 1);
 1435             if (!ref.empty() && !ref["type"].isNull()) {
 1436                 // If the dereference of the current pointer is an ascii character we
 1437                 // might have a string in this address
 1438                 if (ref["type"].toString().contains("ascii")) {
 1439                     buf.resize(128);
 1440                     r_io_read_at(core->io, addr, (unsigned char*)buf.data(), buf.size());
 1441                     QString strVal = QString(buf);
 1442                     // Indicate that the string is longer than the printed value
 1443                     if (strVal.size() == buf.size()) {
 1444                         strVal += "...";
 1445                     }
 1446                     json["string"] = strVal;
 1447                 }
 1448                 json["ref"] = ref;
 1449             }
 1450         }
 1451     }
 1452     return json;
 1453 }
 1454 
 1455 QJsonDocument CutterCore::getProcessThreads(int pid)
 1456 {
 1457     if (-1 == pid) {
 1458         // Return threads list of the currently debugged PID
 1459         return cmdj("dptj");
 1460     } else {
 1461         return cmdj("dptj " + QString::number(pid));
 1462     }
 1463 }
 1464 
 1465 QJsonDocument CutterCore::getChildProcesses(int pid)
 1466 {
 1467     // Return the currently debugged process and it's children
 1468     if (-1 == pid) {
 1469         return cmdj("dpj");
 1470     }
 1471     // Return the given pid and it's child processes
 1472     return cmdj("dpj " + QString::number(pid));
 1473 }
 1474 
 1475 QJsonDocument CutterCore::getRegisterValues()
 1476 {
 1477     return cmdj("drj");
 1478 }
 1479 
 1480 QList<VariableDescription> CutterCore::getVariables(RVA at)
 1481 {
 1482     QList<VariableDescription> ret;
 1483     QJsonObject varsObject = cmdj(QString("afvj @ %1").arg(at)).object();
 1484 
 1485     auto addVars = [&](VariableDescription::RefType refType, const QJsonArray &array) {
 1486         for (const QJsonValue &varValue : array) {
 1487             QJsonObject varObject = varValue.toObject();
 1488             VariableDescription desc;
 1489             desc.refType = refType;
 1490             desc.name = varObject["name"].toString();
 1491             desc.type = varObject["type"].toString();
 1492             ret << desc;
 1493         }
 1494     };
 1495 
 1496     addVars(VariableDescription::RefType::SP, varsObject["sp"].toArray());
 1497     addVars(VariableDescription::RefType::BP, varsObject["bp"].toArray());
 1498     addVars(VariableDescription::RefType::Reg, varsObject["reg"].toArray());
 1499 
 1500     return ret;
 1501 }
 1502 
 1503 QVector<RegisterRefValueDescription> CutterCore::getRegisterRefValues()
 1504 {
 1505     QJsonArray registerRefArray = cmdj("drrj").array();
 1506     QVector<RegisterRefValueDescription> result;
 1507 
 1508     for (const QJsonValue value : registerRefArray) {
 1509         QJsonObject regRefObject = value.toObject();
 1510 
 1511         RegisterRefValueDescription desc;
 1512         desc.name = regRefObject[RJsonKey::reg].toString();
 1513         desc.value = regRefObject[RJsonKey::value].toString();
 1514         desc.ref = regRefObject[RJsonKey::ref].toString();
 1515 
 1516         result.push_back(desc);
 1517     }
 1518     return result;
 1519 }
 1520 
 1521 QString CutterCore::getRegisterName(QString registerRole)
 1522 {
 1523     return cmdRaw("drn " + registerRole).trimmed();
 1524 }
 1525 
 1526 RVA CutterCore::getProgramCounterValue()
 1527 {
 1528     bool ok;
 1529     if (currentlyDebugging) {
 1530         // Use cmd because cmdRaw would not work with inner command backticked
 1531         // TODO: Risky command due to changes in API, search for something safer
 1532         RVA addr = cmd("dr?`drn PC`").toULongLong(&ok, 16);
 1533         if (ok) {
 1534             return addr;
 1535         }
 1536     }
 1537     return RVA_INVALID;
 1538 }
 1539 
 1540 void CutterCore::setRegister(QString regName, QString regValue)
 1541 {
 1542     cmdRaw(QString("dr %1=%2").arg(regName).arg(regValue));
 1543     emit registersChanged();
 1544     emit refreshCodeViews();
 1545 }
 1546 
 1547 void CutterCore::setCurrentDebugThread(int tid)
 1548 {
 1549     if (!asyncCmd("dpt=" + QString::number(tid), debugTask)) {
 1550         return;
 1551     }
 1552 
 1553     emit debugTaskStateChanged();
 1554     connect(debugTask.data(), &R2Task::finished, this, [this] () {
 1555         debugTask.clear();
 1556         emit registersChanged();
 1557         emit refreshCodeViews();
 1558         emit stackChanged();
 1559         syncAndSeekProgramCounter();
 1560         emit switchedThread();
 1561         emit debugTaskStateChanged();
 1562     });
 1563 
 1564     debugTask->startTask();
 1565 }
 1566 
 1567 void CutterCore::setCurrentDebugProcess(int pid)
 1568 {
 1569     if (!currentlyDebugging || !asyncCmd("dp=" + QString::number(pid), debugTask)) {
 1570         return;
 1571     }
 1572 
 1573     emit debugTaskStateChanged();
 1574     connect(debugTask.data(), &R2Task::finished, this, [this] () {
 1575         debugTask.clear();
 1576         emit registersChanged();
 1577         emit refreshCodeViews();
 1578         emit stackChanged();
 1579         emit flagsChanged();
 1580         syncAndSeekProgramCounter();
 1581         emit switchedProcess();
 1582         emit debugTaskStateChanged();
 1583     });
 1584 
 1585     debugTask->startTask();
 1586 }
 1587 
 1588 void CutterCore::startDebug()
 1589 {
 1590     if (!currentlyDebugging) {
 1591         offsetPriorDebugging = getOffset();
 1592     }
 1593     currentlyOpenFile = getConfig("file.path");
 1594 
 1595     if (!asyncCmd("ood", debugTask)) {
 1596         return;
 1597     }
 1598 
 1599     emit debugTaskStateChanged();
 1600 
 1601     connect(debugTask.data(), &R2Task::finished, this, [this] () {
 1602         if (debugTaskDialog) {
 1603             delete debugTaskDialog;
 1604         }
 1605         debugTask.clear();
 1606 
 1607         emit registersChanged();
 1608         if (!currentlyDebugging) {
 1609             setConfig("asm.flags", false);
 1610             currentlyDebugging = true;
 1611             emit toggleDebugView();
 1612             emit refreshCodeViews();
 1613         }
 1614 
 1615         emit codeRebased();
 1616         emit stackChanged();
 1617         emit debugTaskStateChanged();
 1618     });
 1619 
 1620     debugTaskDialog = new R2TaskDialog(debugTask);
 1621     debugTaskDialog->setBreakOnClose(true);
 1622     debugTaskDialog->setAttribute(Qt::WA_DeleteOnClose);
 1623     debugTaskDialog->setDesc(tr("Starting native debug..."));
 1624     debugTaskDialog->show();
 1625 
 1626     debugTask->startTask();
 1627 }
 1628 
 1629 void CutterCore::startEmulation()
 1630 {
 1631     if (!currentlyDebugging) {
 1632         offsetPriorDebugging = getOffset();
 1633     }
 1634 
 1635     // clear registers, init esil state, stack, progcounter at current seek
 1636     asyncCmd("aei; aeim; aeip", debugTask);
 1637 
 1638     emit debugTaskStateChanged();
 1639 
 1640     connect(debugTask.data(), &R2Task::finished, this, [this] () {
 1641         if (debugTaskDialog) {
 1642             delete debugTaskDialog;
 1643         }
 1644         debugTask.clear();
 1645 
 1646         if (!currentlyDebugging || !currentlyEmulating) {
 1647             // prevent register flags from appearing during debug/emul
 1648             setConfig("asm.flags", false);
 1649             // allows to view self-modifying code changes or other binary changes
 1650             setConfig("io.cache", true);
 1651             currentlyDebugging = true;
 1652             currentlyEmulating = true;
 1653             emit toggleDebugView();
 1654         }
 1655 
 1656         emit registersChanged();
 1657         emit stackChanged();
 1658         emit codeRebased();
 1659         emit refreshCodeViews();
 1660         emit debugTaskStateChanged();
 1661     });
 1662 
 1663     debugTaskDialog = new R2TaskDialog(debugTask);
 1664     debugTaskDialog->setBreakOnClose(true);
 1665     debugTaskDialog->setAttribute(Qt::WA_DeleteOnClose);
 1666     debugTaskDialog->setDesc(tr("Starting emulation..."));
 1667     debugTaskDialog->show();
 1668 
 1669     debugTask->startTask();
 1670 }
 1671 
 1672 void CutterCore::attachRemote(const QString &uri)
 1673 {
 1674     if (!currentlyDebugging) {
 1675         offsetPriorDebugging = getOffset();
 1676     }
 1677 
 1678     // connect to a debugger with the given plugin
 1679     asyncCmd("e cfg.debug = true; oodf " + uri, debugTask);
 1680     emit debugTaskStateChanged();
 1681 
 1682     connect(debugTask.data(), &R2Task::finished, this, [this, uri] () {
 1683         if (debugTaskDialog) {
 1684             delete debugTaskDialog;
 1685         }
 1686         debugTask.clear();
 1687         // Check if we actually connected
 1688         bool connected = false;
 1689         QJsonArray openFilesArray = getOpenedFiles();
 1690         for (QJsonValue value : openFilesArray) {
 1691             QJsonObject openFile = value.toObject();
 1692             QString fileUri= openFile["uri"].toString();
 1693             if (!fileUri.compare(uri)) {
 1694                 connected = true;
 1695             }
 1696         }
 1697         // Use cmd because cmdRaw would not with inner command backticked
 1698         QString programCounterValue = cmd("dr?`drn PC`").trimmed();
 1699         seekAndShow(programCounterValue);
 1700         if (!connected) {
 1701             emit attachedRemote(false);
 1702             emit debugTaskStateChanged();
 1703             return;
 1704         }
 1705 
 1706         emit registersChanged();
 1707         if (!currentlyDebugging || !currentlyEmulating) {
 1708             // prevent register flags from appearing during debug/emul
 1709             setConfig("asm.flags", false);
 1710             currentlyDebugging = true;
 1711             emit toggleDebugView();
 1712         }
 1713 
 1714         emit codeRebased();
 1715         emit attachedRemote(true);
 1716         emit debugTaskStateChanged();
 1717     });
 1718 
 1719     debugTaskDialog = new R2TaskDialog(debugTask);
 1720     debugTaskDialog->setBreakOnClose(true);
 1721     debugTaskDialog->setAttribute(Qt::WA_DeleteOnClose);
 1722     debugTaskDialog->setDesc(tr("Connecting to: ") + uri);
 1723     debugTaskDialog->show();
 1724 
 1725     debugTask->startTask();
 1726 }
 1727 
 1728 void CutterCore::attachDebug(int pid)
 1729 {
 1730     if (!currentlyDebugging) {
 1731         offsetPriorDebugging = getOffset();
 1732     }
 1733 
 1734     // attach to process with dbg plugin
 1735     asyncCmd("e cfg.debug = true; oodf dbg://" + QString::number(pid), debugTask);
 1736     emit debugTaskStateChanged();
 1737 
 1738     connect(debugTask.data(), &R2Task::finished, this, [this, pid] () {
 1739         if (debugTaskDialog) {
 1740             delete debugTaskDialog;
 1741         }
 1742         debugTask.clear();
 1743 
 1744         syncAndSeekProgramCounter();
 1745         if (!currentlyDebugging || !currentlyEmulating) {
 1746             // prevent register flags from appearing during debug/emul
 1747             setConfig("asm.flags", false);
 1748             currentlyDebugging = true;
 1749             currentlyOpenFile = getConfig("file.path");
 1750             currentlyAttachedToPID = pid;
 1751             emit toggleDebugView();
 1752         }
 1753 
 1754         emit codeRebased();
 1755         emit debugTaskStateChanged();
 1756     });
 1757 
 1758     debugTaskDialog = new R2TaskDialog(debugTask);
 1759     debugTaskDialog->setBreakOnClose(true);
 1760     debugTaskDialog->setAttribute(Qt::WA_DeleteOnClose);
 1761     debugTaskDialog->setDesc(tr("Attaching to process (") + QString::number(pid) + ")...");
 1762     debugTaskDialog->show();
 1763 
 1764     debugTask->startTask();
 1765 }
 1766 
 1767 void CutterCore::suspendDebug()
 1768 {
 1769     debugTask->breakTask();
 1770 }
 1771 
 1772 void CutterCore::stopDebug()
 1773 {
 1774     if (!currentlyDebugging) {
 1775         return;
 1776     }
 1777 
 1778     if (!debugTask.isNull()) {
 1779         suspendDebug();
 1780     }
 1781 
 1782     currentlyDebugging = false;
 1783     emit debugTaskStateChanged();
 1784 
 1785     if (currentlyEmulating) {
 1786         cmdEsil("aeim-; aei-; wcr; .ar-");
 1787         currentlyEmulating = false;
 1788     } else if (currentlyAttachedToPID != -1) {
 1789         // Use cmd because cmdRaw would not work with command concatenation
 1790         cmd(QString("dp- %1; o %2; .ar-").arg(
 1791             QString::number(currentlyAttachedToPID), currentlyOpenFile));
 1792         currentlyAttachedToPID = -1;
 1793     } else {
 1794         QString ptraceFiles = "";
 1795         // close ptrace file descriptors left open
 1796         QJsonArray openFilesArray = cmdj("oj").array();;
 1797         for (QJsonValue value : openFilesArray) {
 1798             QJsonObject openFile = value.toObject();
 1799             QString URI = openFile["uri"].toString();
 1800             if (URI.contains("ptrace")) {
 1801                 ptraceFiles += "o-" + QString::number(openFile["fd"].toInt()) + ";";
 1802             }
 1803         }
 1804         // Use cmd because cmdRaw would not work with command concatenation
 1805         cmd("doc" + ptraceFiles);
 1806     }
 1807 
 1808     syncAndSeekProgramCounter();
 1809     setConfig("asm.flags", true);
 1810     setConfig("io.cache", false);
 1811     emit codeRebased();
 1812     emit toggleDebugView();
 1813     offsetPriorDebugging = getOffset();
 1814     emit debugTaskStateChanged();
 1815 }
 1816 
 1817 void CutterCore::syncAndSeekProgramCounter()
 1818 {
 1819     // Use cmd because cmdRaw would not work with inner command backticked
 1820     QString programCounterValue = cmd("dr?`drn PC`").trimmed();
 1821     seekAndShow(programCounterValue);
 1822     emit registersChanged();
 1823 }
 1824 
 1825 void CutterCore::continueDebug()
 1826 {
 1827     if (!currentlyDebugging) {
 1828         return;
 1829     }
 1830 
 1831     if (currentlyEmulating) {
 1832         if (!asyncCmdEsil("aec", debugTask)) {
 1833             return;
 1834         }
 1835     } else {
 1836         if (!asyncCmd("dc", debugTask)) {
 1837             return;
 1838         }
 1839     }
 1840 
 1841     emit debugTaskStateChanged();
 1842     connect(debugTask.data(), &R2Task::finished, this, [this] () {
 1843         debugTask.clear();
 1844         syncAndSeekProgramCounter();
 1845         emit registersChanged();
 1846         emit refreshCodeViews();
 1847         emit debugTaskStateChanged();
 1848     });
 1849 
 1850     debugTask->startTask();
 1851 }
 1852 
 1853 void CutterCore::continueUntilDebug(QString offset)
 1854 {
 1855     if (!currentlyDebugging) {
 1856         return;
 1857     }
 1858 
 1859     if (currentlyEmulating) {
 1860         if (!asyncCmdEsil("aecu " + offset, debugTask)) {
 1861             return;
 1862         }
 1863     } else {
 1864         if (!asyncCmd("dcu " + offset, debugTask)) {
 1865             return;
 1866         }
 1867     }
 1868 
 1869     emit debugTaskStateChanged();
 1870     connect(debugTask.data(), &R2Task::finished, this, [this] () {
 1871         debugTask.clear();
 1872         syncAndSeekProgramCounter();
 1873         emit registersChanged();
 1874         emit stackChanged();
 1875         emit refreshCodeViews();
 1876         emit debugTaskStateChanged();
 1877     });
 1878 
 1879     debugTask->startTask();
 1880 }
 1881 
 1882 void CutterCore::continueUntilCall()
 1883 {
 1884     if (!currentlyDebugging) {
 1885         return;
 1886     }
 1887 
 1888     if (currentlyEmulating) {
 1889         if (!asyncCmdEsil("aecc", debugTask)) {
 1890             return;
 1891         }
 1892     } else {
 1893         if (!asyncCmd("dcc", debugTask)) {
 1894             return;
 1895         }
 1896     }
 1897 
 1898     emit debugTaskStateChanged();
 1899     connect(debugTask.data(), &R2Task::finished, this, [this] () {
 1900         debugTask.clear();
 1901         syncAndSeekProgramCounter();
 1902         emit debugTaskStateChanged();
 1903     });
 1904 
 1905     debugTask->startTask();
 1906 }
 1907 
 1908 void CutterCore::continueUntilSyscall()
 1909 {
 1910     if (!currentlyDebugging) {
 1911         return;
 1912     }
 1913 
 1914     if (currentlyEmulating) {
 1915         if (!asyncCmdEsil("aecs", debugTask)) {
 1916             return;
 1917         }
 1918     } else {
 1919         if (!asyncCmd("dcs", debugTask)) {
 1920             return;
 1921         }
 1922     }
 1923 
 1924     emit debugTaskStateChanged();
 1925     connect(debugTask.data(), &R2Task::finished, this, [this] () {
 1926         debugTask.clear();
 1927         syncAndSeekProgramCounter();
 1928         emit debugTaskStateChanged();
 1929     });
 1930 
 1931     debugTask->startTask();
 1932 }
 1933 
 1934 void CutterCore::stepDebug()
 1935 {
 1936     if (!currentlyDebugging) {
 1937         return;
 1938     }
 1939 
 1940     if (currentlyEmulating) {
 1941         if (!asyncCmdEsil("aes", debugTask)) {
 1942             return;
 1943         }
 1944     } else {
 1945         if (!asyncCmd("ds", debugTask)) {
 1946             return;
 1947         }
 1948     }
 1949 
 1950     emit debugTaskStateChanged();
 1951     connect(debugTask.data(), &R2Task::finished, this, [this] () {
 1952         debugTask.clear();
 1953         syncAndSeekProgramCounter();
 1954         emit debugTaskStateChanged();
 1955     });
 1956 
 1957     debugTask->startTask();
 1958 }
 1959 
 1960 void CutterCore::stepOverDebug()
 1961 {
 1962     if (!currentlyDebugging) {
 1963         return;
 1964     }
 1965 
 1966     if (currentlyEmulating) {
 1967         if (!asyncCmdEsil("aeso", debugTask)) {
 1968             return;
 1969         }
 1970     } else {
 1971         if (!asyncCmd("dso", debugTask)) {
 1972             return;
 1973         }
 1974     }
 1975 
 1976     emit debugTaskStateChanged();
 1977     connect(debugTask.data(), &R2Task::finished, this, [this] () {
 1978         debugTask.clear();
 1979         syncAndSeekProgramCounter();
 1980         emit debugTaskStateChanged();
 1981     });
 1982 
 1983     debugTask->startTask();
 1984 }
 1985 
 1986 void CutterCore::stepOutDebug()
 1987 {
 1988     if (!currentlyDebugging) {
 1989         return;
 1990     }
 1991 
 1992     emit debugTaskStateChanged();
 1993     if (!asyncCmd("dsf", debugTask)) {
 1994         return;
 1995     }
 1996 
 1997     connect(debugTask.data(), &R2Task::finished, this, [this] () {
 1998         debugTask.clear();
 1999         syncAndSeekProgramCounter();
 2000         emit debugTaskStateChanged();
 2001     });
 2002 
 2003     debugTask->startTask();
 2004 }
 2005 
 2006 QStringList CutterCore::getDebugPlugins()
 2007 {
 2008     QStringList plugins;
 2009     QJsonArray pluginArray = cmdj("dLj").array();
 2010 
 2011     for (const QJsonValue &value : pluginArray) {
 2012         QJsonObject pluginObject = value.toObject();
 2013 
 2014         QString plugin = pluginObject[RJsonKey::name].toString();
 2015 
 2016         plugins << plugin;
 2017     }
 2018     return plugins;
 2019 }
 2020 
 2021 QString CutterCore::getActiveDebugPlugin()
 2022 {
 2023     return getConfig("dbg.backend");
 2024 }
 2025 
 2026 void CutterCore::setDebugPlugin(QString plugin)
 2027 {
 2028     setConfig("dbg.backend", plugin);
 2029 }
 2030 
 2031 void CutterCore::toggleBreakpoint(RVA addr)
 2032 {
 2033     cmdRaw(QString("dbs %1").arg(addr));
 2034     emit instructionChanged(addr);
 2035     emit breakpointsChanged();
 2036 }
 2037 
 2038 void CutterCore::toggleBreakpoint(QString addr)
 2039 {
 2040     cmdRaw("dbs " + addr);
 2041     emit instructionChanged(addr.toULongLong());
 2042     emit breakpointsChanged();
 2043 }
 2044 
 2045 
 2046 void CutterCore::addBreakpoint(QString addr)
 2047 {
 2048     cmdRaw("db " + addr);
 2049     emit instructionChanged(addr.toULongLong());
 2050     emit breakpointsChanged();
 2051 }
 2052 
 2053 void CutterCore::addBreakpoint(const BreakpointDescription &config)
 2054 {
 2055     CORE_LOCK();
 2056     RBreakpointItem *breakpoint = nullptr;
 2057     int watchpoint_prot = 0;
 2058     if (config.hw) {
 2059         watchpoint_prot = config.permission & ~(R_BP_PROT_EXEC);
 2060     }
 2061 
 2062     auto address = config.addr;
 2063     char *module = nullptr;
 2064     QByteArray moduleNameData;
 2065     if (config.type == BreakpointDescription::Named) {
 2066         address = Core()->math(config.positionExpression);
 2067     } else if (config.type == BreakpointDescription::Module) {
 2068         address = 0;
 2069         moduleNameData = config.positionExpression.toUtf8();
 2070         module = moduleNameData.data();
 2071     }
 2072     breakpoint = r_debug_bp_add(core->dbg, address, (config.hw && watchpoint_prot == 0),
 2073                                 watchpoint_prot, watchpoint_prot,
 2074                                 module, config.moduleDelta);
 2075     if (!breakpoint) {
 2076         QMessageBox::critical(nullptr, tr("Breakpoint error"), tr("Failed to create breakpoint"));
 2077         return;
 2078     }
 2079     if (config.type == BreakpointDescription::Named) {
 2080         updateOwnedCharPtr(breakpoint->expr, config.positionExpression);
 2081     }
 2082 
 2083     if (config.hw) {
 2084         breakpoint->size = config.size;
 2085     }
 2086     if (config.type == BreakpointDescription::Named) {
 2087         updateOwnedCharPtr(breakpoint->name, config.positionExpression);
 2088     }
 2089 
 2090     int index = std::find(core->dbg->bp->bps_idx,
 2091                           core->dbg->bp->bps_idx + core->dbg->bp->bps_idx_count,
 2092                           breakpoint) - core->dbg->bp->bps_idx;
 2093 
 2094     breakpoint->enabled = config.enabled;
 2095     if (config.trace) {
 2096         setBreakpointTrace(index, config.trace);
 2097     }
 2098     if (!config.condition.isEmpty()) {
 2099         updateOwnedCharPtr(breakpoint->cond, config.condition);
 2100     }
 2101     if (!config.command.isEmpty()) {
 2102         updateOwnedCharPtr(breakpoint->data, config.command);
 2103     }
 2104     emit instructionChanged(breakpoint->addr);
 2105     emit breakpointsChanged();
 2106 }
 2107 
 2108 void CutterCore::updateBreakpoint(int index, const BreakpointDescription &config)
 2109 {
 2110     CORE_LOCK();
 2111     if (auto bp = r_bp_get_index(core->dbg->bp, index)) {
 2112         r_bp_del(core->dbg->bp, bp->addr);
 2113     }
 2114     // Delete by index currently buggy,
 2115     // required for breakpoints with non address based position
 2116     //r_bp_del_index(core->dbg->bp, index);
 2117     addBreakpoint(config);
 2118 }
 2119 
 2120 void CutterCore::delBreakpoint(RVA addr)
 2121 {
 2122     cmdRaw("db- " + RAddressString(addr));
 2123     emit instructionChanged(addr);
 2124     emit breakpointsChanged();
 2125 }
 2126 
 2127 void CutterCore::delAllBreakpoints()
 2128 {
 2129     cmdRaw("db-*");
 2130     emit refreshCodeViews();
 2131 }
 2132 
 2133 void CutterCore::enableBreakpoint(RVA addr)
 2134 {
 2135     cmdRaw("dbe " + RAddressString(addr));
 2136     emit instructionChanged(addr);
 2137     emit breakpointsChanged();
 2138 }
 2139 
 2140 void CutterCore::disableBreakpoint(RVA addr)
 2141 {
 2142     cmdRaw("dbd " + RAddressString(addr));
 2143     emit instructionChanged(addr);
 2144     emit breakpointsChanged();
 2145 }
 2146 
 2147 void CutterCore::setBreakpointTrace(int index, bool enabled)
 2148 {
 2149     if (enabled) {
 2150         cmdRaw(QString("dbite %1").arg(index));
 2151     } else {
 2152         cmdRaw(QString("dbitd %1").arg(index));
 2153     }
 2154 }
 2155 
 2156 static BreakpointDescription breakpointDescriptionFromR2(int index, r_bp_item_t *bpi)
 2157 {
 2158     BreakpointDescription bp;
 2159     bp.addr = bpi->addr;
 2160     bp.index = index;
 2161     bp.size = bpi->size;
 2162     if (bpi->expr) {
 2163         bp.positionExpression = bpi->expr;
 2164         bp.type = BreakpointDescription::Named;
 2165     }
 2166     bp.name = bpi->name;
 2167     bp.permission = bpi->perm;
 2168     bp.command = bpi->data;
 2169     bp.condition = bpi->cond;
 2170     bp.hw = bpi->hw;
 2171     bp.trace = bpi->trace;
 2172     bp.enabled = bpi->enabled;
 2173     return bp;
 2174 }
 2175 
 2176 int CutterCore::breakpointIndexAt(RVA addr)
 2177 {
 2178     CORE_LOCK();
 2179     return r_bp_get_index_at(core->dbg->bp, addr);
 2180 }
 2181 
 2182 BreakpointDescription CutterCore::getBreakpointAt(RVA addr)
 2183 {
 2184     CORE_LOCK();
 2185     int index = breakpointIndexAt(addr);
 2186     auto bp = r_bp_get_index(core->dbg->bp, index);
 2187     if (bp) {
 2188         return breakpointDescriptionFromR2(index, bp);
 2189     }
 2190     return BreakpointDescription();
 2191 }
 2192 
 2193 QList<BreakpointDescription> CutterCore::getBreakpoints()
 2194 {
 2195     CORE_LOCK();
 2196     QList<BreakpointDescription> ret;
 2197     //TODO: use higher level API, don't touch r2 bps_idx directly
 2198     for (int i = 0; i < core->dbg->bp->bps_idx_count; i++) {
 2199         if (auto bpi = core->dbg->bp->bps_idx[i]) {
 2200             ret.push_back(breakpointDescriptionFromR2(i, bpi));
 2201         }
 2202     }
 2203 
 2204     return ret;
 2205 }
 2206 
 2207 
 2208 QList<RVA> CutterCore::getBreakpointsAddresses()
 2209 {
 2210     QList<RVA> bpAddresses;
 2211     for (const BreakpointDescription &bp : getBreakpoints()) {
 2212         bpAddresses << bp.addr;
 2213     }
 2214 
 2215     return bpAddresses;
 2216 }
 2217 
 2218 QList<RVA> CutterCore::getBreakpointsInFunction(RVA funcAddr)
 2219 {
 2220     QList<RVA> allBreakpoints = getBreakpointsAddresses();
 2221     QList<RVA> functionBreakpoints;
 2222 
 2223     // Use std manipulations to take only the breakpoints that belong to this function
 2224     std::copy_if(allBreakpoints.begin(),
 2225              allBreakpoints.end(),
 2226              std::back_inserter(functionBreakpoints),
 2227              [this, funcAddr](RVA BPadd) { return getFunctionStart(BPadd) == funcAddr; });
 2228     return functionBreakpoints;
 2229 }
 2230 
 2231 bool CutterCore::isBreakpoint(const QList<RVA> &breakpoints, RVA addr)
 2232 {
 2233     return breakpoints.contains(addr);
 2234 }
 2235 
 2236 QJsonDocument CutterCore::getBacktrace()
 2237 {
 2238     return cmdj("dbtj");
 2239 }
 2240 
 2241 QList<ProcessDescription> CutterCore::getAllProcesses()
 2242 {
 2243     QList<ProcessDescription> ret;
 2244     QJsonArray processArray = cmdj("dplj").array();
 2245 
 2246     for (const QJsonValue &value : processArray) {
 2247         QJsonObject procObject = value.toObject();
 2248 
 2249         ProcessDescription proc;
 2250 
 2251         proc.pid = procObject[RJsonKey::pid].toInt();
 2252         proc.uid = procObject[RJsonKey::uid].toInt();
 2253         proc.status = procObject[RJsonKey::status].toString();
 2254         proc.path = procObject[RJsonKey::path].toString();
 2255 
 2256         ret << proc;
 2257     }
 2258 
 2259     return ret;
 2260 }
 2261 
 2262 QList<MemoryMapDescription> CutterCore::getMemoryMap()
 2263 {
 2264     QList<MemoryMapDescription> ret;
 2265     QJsonArray memoryMapArray = cmdj("dmj").array();
 2266 
 2267     for (const QJsonValue &value : memoryMapArray) {
 2268         QJsonObject memMapObject = value.toObject();
 2269 
 2270         MemoryMapDescription memMap;
 2271 
 2272         memMap.name = memMapObject[RJsonKey::name].toString();
 2273         memMap.fileName = memMapObject[RJsonKey::file].toString();
 2274         memMap.addrStart = memMapObject[RJsonKey::addr].toVariant().toULongLong();
 2275         memMap.addrEnd = memMapObject[RJsonKey::addr_end].toVariant().toULongLong();
 2276         memMap.type = memMapObject[RJsonKey::type].toString();
 2277         memMap.permission = memMapObject[RJsonKey::perm].toString();
 2278 
 2279         ret << memMap;
 2280     }
 2281 
 2282     return ret;
 2283 }
 2284 
 2285 QStringList CutterCore::getStats()
 2286 {
 2287     QStringList stats;
 2288     cmdRaw("fs functions");
 2289 
 2290     // The cmd coomand is frequently used in this function because
 2291     // cmdRaw would not work with grep
 2292     stats << cmd("f~?").trimmed();
 2293 
 2294     QString imps = cmd("ii~?").trimmed();
 2295     stats << imps;
 2296 
 2297     cmdRaw("fs symbols");
 2298     stats << cmd("f~?").trimmed();
 2299     cmdRaw("fs strings");
 2300     stats << cmd("f~?").trimmed();
 2301     cmdRaw("fs relocs");
 2302     stats << cmd("f~?").trimmed();
 2303     cmdRaw("fs sections");
 2304     stats << cmd("f~?").trimmed();
 2305     cmdRaw("fs *");
 2306     stats << cmd("f~?").trimmed();
 2307 
 2308     return stats;
 2309 }
 2310 
 2311 void CutterCore::setGraphEmpty(bool empty)
 2312 {
 2313     emptyGraph = empty;
 2314 }
 2315 
 2316 bool CutterCore::isGraphEmpty()
 2317 {
 2318     return emptyGraph;
 2319 }
 2320 
 2321 void CutterCore::getOpcodes()
 2322 {
 2323     this->opcodes = cmdList("?O");
 2324     this->regs = cmdList("drp~[1]");
 2325 }
 2326 
 2327 void CutterCore::setSettings()
 2328 {
 2329     setConfig("scr.interactive", false);
 2330 
 2331     setConfig("hex.pairs", false);
 2332     setConfig("asm.xrefs", false);
 2333 
 2334     setConfig("asm.tabs.once", true);
 2335     setConfig("asm.flags.middle", 2);
 2336 
 2337     setConfig("anal.hasnext", false);
 2338     setConfig("asm.lines.call", false);
 2339 
 2340     setConfig("cfg.fortunes.tts", false);
 2341 
 2342     // Colors
 2343     setConfig("scr.color", COLOR_MODE_DISABLED);
 2344 
 2345     // Don't show hits
 2346     setConfig("search.flags", false);
 2347 }
 2348 
 2349 QList<RVA> CutterCore::getSeekHistory()
 2350 {
 2351     CORE_LOCK();
 2352     QList<RVA> ret;
 2353 
 2354     QJsonArray jsonArray = cmdj("sj").array();
 2355     for (const QJsonValue &value : jsonArray)
 2356         ret << value.toVariant().toULongLong();
 2357 
 2358     return ret;
 2359 }
 2360 
 2361 QStringList CutterCore::getAsmPluginNames()
 2362 {
 2363     CORE_LOCK();
 2364     RListIter *it;
 2365     QStringList ret;
 2366 
 2367     RAsmPlugin *ap;
 2368     CutterRListForeach(core->assembler->plugins, it, RAsmPlugin, ap) {
 2369         ret << ap->name;
 2370     }
 2371 
 2372     return ret;
 2373 }
 2374 
 2375 QStringList CutterCore::getAnalPluginNames()
 2376 {
 2377     CORE_LOCK();
 2378     RListIter *it;
 2379     QStringList ret;
 2380 
 2381     RAnalPlugin *ap;
 2382     CutterRListForeach(core->anal->plugins, it, RAnalPlugin, ap) {
 2383         ret << ap->name;
 2384     }
 2385 
 2386     return ret;
 2387 }
 2388 
 2389 QStringList CutterCore::getProjectNames()
 2390 {
 2391     CORE_LOCK();
 2392     QStringList ret;
 2393 
 2394     QJsonArray jsonArray = cmdj("Pj").array();
 2395     for (const QJsonValue &value : jsonArray)
 2396         ret.append(value.toString());
 2397 
 2398     return ret;
 2399 }
 2400 
 2401 QList<RBinPluginDescription> CutterCore::getRBinPluginDescriptions(const QString &type)
 2402 {
 2403     QList<RBinPluginDescription> ret;
 2404 
 2405     QJsonObject jsonRoot = cmdj("iLj").object();
 2406     for (const QString &key : jsonRoot.keys()) {
 2407         if (!type.isNull() && key != type)
 2408             continue;
 2409 
 2410         QJsonArray pluginArray = jsonRoot[key].toArray();
 2411 
 2412         for (const QJsonValue &pluginValue : pluginArray) {
 2413             QJsonObject pluginObject = pluginValue.toObject();
 2414 
 2415             RBinPluginDescription desc;
 2416 
 2417             desc.name = pluginObject[RJsonKey::name].toString();
 2418             desc.description = pluginObject[RJsonKey::description].toString();
 2419             desc.license = pluginObject[RJsonKey::license].toString();
 2420             desc.type = key;
 2421 
 2422             ret.append(desc);
 2423         }
 2424     }
 2425 
 2426     return ret;
 2427 }
 2428 
 2429 QList<RIOPluginDescription> CutterCore::getRIOPluginDescriptions()
 2430 {
 2431     QList<RIOPluginDescription> ret;
 2432 
 2433     QJsonArray plugins = cmdj("oLj").object()["io_plugins"].toArray();
 2434     for (const QJsonValue &pluginValue : plugins) {
 2435         QJsonObject pluginObject = pluginValue.toObject();
 2436 
 2437         RIOPluginDescription plugin;
 2438 
 2439         plugin.name = pluginObject["name"].toString();
 2440         plugin.description = pluginObject["description"].toString();
 2441         plugin.license = pluginObject["license"].toString();
 2442         plugin.permissions = pluginObject["permissions"].toString();
 2443         for (const auto &uri : pluginObject["uris"].toArray()) {
 2444             plugin.uris << uri.toString();
 2445         }
 2446 
 2447         ret << plugin;
 2448     }
 2449 
 2450     return ret;
 2451 }
 2452 
 2453 QList<RCorePluginDescription> CutterCore::getRCorePluginDescriptions()
 2454 {
 2455     QList<RCorePluginDescription> ret;
 2456 
 2457     QJsonArray plugins = cmdj("Lsj").array();
 2458     for (const QJsonValue &pluginValue : plugins) {
 2459         QJsonObject pluginObject = pluginValue.toObject();
 2460 
 2461         RCorePluginDescription plugin;
 2462 
 2463         plugin.name = pluginObject["Name"].toString();
 2464         plugin.description = pluginObject["Description"].toString();
 2465 
 2466         ret << plugin;
 2467     }
 2468 
 2469     return ret;
 2470 }
 2471 
 2472 QList<RAsmPluginDescription> CutterCore::getRAsmPluginDescriptions()
 2473 {
 2474     CORE_LOCK();
 2475     RListIter *it;
 2476     QList<RAsmPluginDescription> ret;
 2477 
 2478     RAsmPlugin *ap;
 2479     CutterRListForeach(core->assembler->plugins, it, RAsmPlugin, ap) {
 2480         RAsmPluginDescription plugin;
 2481 
 2482         plugin.name = ap->name;
 2483         plugin.architecture = ap->arch;
 2484         plugin.author = ap->author;
 2485         plugin.version = ap->version;
 2486         plugin.cpus = ap->cpus;
 2487         plugin.description = ap->desc;
 2488         plugin.license = ap->license;
 2489 
 2490         ret << plugin;
 2491     }
 2492 
 2493     return ret;
 2494 }
 2495 
 2496 QList<FunctionDescription> CutterCore::getAllFunctions()
 2497 {
 2498     CORE_LOCK();
 2499 
 2500     QList<FunctionDescription> funcList;
 2501     funcList.reserve(r_list_length(core->anal->fcns));
 2502 
 2503     RListIter *iter;
 2504     RAnalFunction *fcn;
 2505     CutterRListForeach (core->anal->fcns, iter, RAnalFunction, fcn) {
 2506         FunctionDescription function;
 2507         function.offset = fcn->addr;
 2508         function.linearSize = r_anal_function_linear_size(fcn);
 2509         function.nargs = r_anal_var_count(core->anal, fcn, 'b', 1) +
 2510             r_anal_var_count(core->anal, fcn, 'r', 1) +
 2511             r_anal_var_count(core->anal, fcn, 's', 1);
 2512         function.nlocals = r_anal_var_count(core->anal, fcn, 'b', 0) +
 2513             r_anal_var_count(core->anal, fcn, 'r', 0) +
 2514             r_anal_var_count(core->anal, fcn, 's', 0);
 2515         function.nbbs = r_list_length (fcn->bbs);
 2516         function.calltype = fcn->cc ? QString::fromUtf8(fcn->cc) : QString();
 2517         function.name = fcn->name ? QString::fromUtf8(fcn->name) : QString();
 2518         function.edges = r_anal_function_count_edges(fcn, nullptr);
 2519         function.stackframe = fcn->maxstack;
 2520         funcList.append(function);
 2521     }
 2522 
 2523     return funcList;
 2524 }
 2525 
 2526 QList<ImportDescription> CutterCore::getAllImports()
 2527 {
 2528     CORE_LOCK();
 2529     QList<ImportDescription> ret;
 2530 
 2531     QJsonArray importsArray = cmdj("iij").array();
 2532 
 2533     for (const QJsonValue &value : importsArray) {
 2534         QJsonObject importObject = value.toObject();
 2535 
 2536         ImportDescription import;
 2537 
 2538         import.plt = importObject[RJsonKey::plt].toVariant().toULongLong();
 2539         import.ordinal = importObject[RJsonKey::ordinal].toInt();
 2540         import.bind = importObject[RJsonKey::bind].toString();
 2541         import.type = importObject[RJsonKey::type].toString();
 2542         import.libname = importObject[RJsonKey::libname].toString();
 2543         import.name = importObject[RJsonKey::name].toString();
 2544 
 2545         ret << import;
 2546     }
 2547 
 2548     return ret;
 2549 }
 2550 
 2551 QList<ExportDescription> CutterCore::getAllExports()
 2552 {
 2553     CORE_LOCK();
 2554     QList<ExportDescription> ret;
 2555 
 2556     QJsonArray exportsArray = cmdj("iEj").array();
 2557 
 2558     for (const QJsonValue &value : exportsArray) {
 2559         QJsonObject exportObject = value.toObject();
 2560 
 2561         ExportDescription exp;
 2562 
 2563         exp.vaddr = exportObject[RJsonKey::vaddr].toVariant().toULongLong();
 2564         exp.paddr = exportObject[RJsonKey::paddr].toVariant().toULongLong();
 2565         exp.size = exportObject[RJsonKey::size].toVariant().toULongLong();
 2566         exp.type = exportObject[RJsonKey::type].toString();
 2567         exp.name = exportObject[RJsonKey::name].toString();
 2568         exp.flag_name = exportObject[RJsonKey::flagname].toString();
 2569 
 2570         ret << exp;
 2571     }
 2572 
 2573     return ret;
 2574 }
 2575 
 2576 QList<SymbolDescription> CutterCore::getAllSymbols()
 2577 {
 2578     CORE_LOCK();
 2579     RListIter *it;
 2580 
 2581     QList<SymbolDescription> ret;
 2582 
 2583     RBinSymbol *bs;
 2584     if (core && core->bin && core->bin->cur && core->bin->cur->o) {
 2585         CutterRListForeach(core->bin->cur->o->symbols, it, RBinSymbol, bs) {
 2586             QString type = QString(bs->bind) + " " + QString(bs->type);
 2587             SymbolDescription symbol;
 2588             symbol.vaddr = bs->vaddr;
 2589             symbol.name = QString(bs->name);
 2590             symbol.bind = QString(bs->bind);
 2591             symbol.type = QString(bs->type);
 2592             ret << symbol;
 2593         }
 2594 
 2595         /* list entrypoints as symbols too */
 2596         int n = 0;
 2597         RBinAddr *entry;
 2598         CutterRListForeach(core->bin->cur->o->entries, it, RBinAddr, entry) {
 2599             SymbolDescription symbol;
 2600             symbol.vaddr = entry->vaddr;
 2601             symbol.name = QString("entry") + QString::number(n++);
 2602             symbol.bind.clear();
 2603             symbol.type = "entry";
 2604             ret << symbol;
 2605         }
 2606     }
 2607 
 2608     return ret;
 2609 }
 2610 
 2611 QList<HeaderDescription> CutterCore::getAllHeaders()
 2612 {
 2613     CORE_LOCK();
 2614     QList<HeaderDescription> ret;
 2615 
 2616     QJsonArray headersArray = cmdj("ihj").array();
 2617 
 2618     for (const QJsonValue &value : headersArray) {
 2619         QJsonObject headerObject = value.toObject();
 2620 
 2621         HeaderDescription header;
 2622 
 2623         header.vaddr = headerObject[RJsonKey::vaddr].toVariant().toULongLong();
 2624         header.paddr = headerObject[RJsonKey::paddr].toVariant().toULongLong();
 2625         header.value = headerObject[RJsonKey::comment].toString();
 2626         header.name = headerObject[RJsonKey::name].toString();
 2627 
 2628         ret << header;
 2629     }
 2630 
 2631     return ret;
 2632 }
 2633 
 2634 QList<ZignatureDescription> CutterCore::getAllZignatures()
 2635 {
 2636     CORE_LOCK();
 2637     QList<ZignatureDescription> zignatures;
 2638 
 2639     QJsonArray zignaturesArray = cmdj("zj").array();
 2640 
 2641     for (const QJsonValue &value : zignaturesArray) {
 2642         QJsonObject zignatureObject = value.toObject();
 2643 
 2644         ZignatureDescription zignature;
 2645 
 2646         zignature.name = zignatureObject[RJsonKey::name].toString();
 2647         zignature.bytes = zignatureObject[RJsonKey::bytes].toString();
 2648         zignature.offset = zignatureObject[RJsonKey::offset].toVariant().toULongLong();
 2649         for (const QJsonValue &ref : zignatureObject[RJsonKey::refs].toArray()) {
 2650             zignature.refs << ref.toString();
 2651         }
 2652 
 2653         QJsonObject graphObject = zignatureObject[RJsonKey::graph].toObject();
 2654         zignature.cc = graphObject[RJsonKey::cc].toVariant().toULongLong();
 2655         zignature.nbbs = graphObject[RJsonKey::nbbs].toVariant().toULongLong();
 2656         zignature.edges = graphObject[RJsonKey::edges].toVariant().toULongLong();
 2657         zignature.ebbs = graphObject[RJsonKey::ebbs].toVariant().toULongLong();
 2658 
 2659         zignatures << zignature;
 2660     }
 2661 
 2662     return zignatures;
 2663 }
 2664 
 2665 QList<CommentDescription> CutterCore::getAllComments(const QString &filterType)
 2666 {
 2667     CORE_LOCK();
 2668     QList<CommentDescription> ret;
 2669 
 2670     QJsonArray commentsArray = cmdj("CCj").array();
 2671     for (const QJsonValue &value : commentsArray) {
 2672         QJsonObject commentObject = value.toObject();
 2673 
 2674         QString type = commentObject[RJsonKey::type].toString();
 2675         if (type != filterType)
 2676             continue;
 2677 
 2678         CommentDescription comment;
 2679         comment.offset = commentObject[RJsonKey::offset].toVariant().toULongLong();
 2680         comment.name = commentObject[RJsonKey::name].toString();
 2681 
 2682         ret << comment;
 2683     }
 2684     return ret;
 2685 }
 2686 
 2687 QList<RelocDescription> CutterCore::getAllRelocs()
 2688 {
 2689     CORE_LOCK();
 2690     QList<RelocDescription> ret;
 2691 
 2692     if (core && core->bin && core->bin->cur && core->bin->cur->o) {
 2693         auto relocs = core->bin->cur->o->relocs;
 2694         RBIter iter;
 2695         RBinReloc *br;
 2696         r_rbtree_foreach (relocs, iter, br, RBinReloc, vrb) {
 2697             RelocDescription reloc;
 2698 
 2699             reloc.vaddr = br->vaddr;
 2700             reloc.paddr = br->paddr;
 2701             reloc.type = (br->additive ? "ADD_" : "SET_") + QString::number(br->type);
 2702 
 2703             if (br->import)
 2704                 reloc.name = br->import->name;
 2705             else
 2706                 reloc.name = QString("reloc_%1").arg(QString::number(br->vaddr, 16));
 2707 
 2708             ret << reloc;
 2709         }
 2710     }
 2711 
 2712     return ret;
 2713 }
 2714 
 2715 QList<StringDescription> CutterCore::getAllStrings()
 2716 {
 2717     return parseStringsJson(cmdjTask("izzj"));
 2718 }
 2719 
 2720 QList<StringDescription> CutterCore::parseStringsJson(const QJsonDocument &doc)
 2721 {
 2722     QList<StringDescription> ret;
 2723 
 2724     QJsonArray stringsArray = doc.array();
 2725     for (const QJsonValue &value : stringsArray) {
 2726         QJsonObject stringObject = value.toObject();
 2727 
 2728         StringDescription string;
 2729 
 2730         string.string = stringObject[RJsonKey::string].toString();
 2731         string.vaddr = stringObject[RJsonKey::vaddr].toVariant().toULongLong();
 2732         string.type = stringObject[RJsonKey::type].toString();
 2733         string.size = stringObject[RJsonKey::size].toVariant().toUInt();
 2734         string.length = stringObject[RJsonKey::length].toVariant().toUInt();
 2735         string.section = stringObject[RJsonKey::section].toString();
 2736 
 2737         ret << string;
 2738     }
 2739 
 2740     return ret;
 2741 }
 2742 
 2743 QList<FlagspaceDescription> CutterCore::getAllFlagspaces()
 2744 {
 2745     CORE_LOCK();
 2746     QList<FlagspaceDescription> ret;
 2747 
 2748     QJsonArray flagspacesArray = cmdj("fsj").array();
 2749     for (const QJsonValue &value : flagspacesArray) {
 2750         QJsonObject flagspaceObject = value.toObject();
 2751 
 2752         FlagspaceDescription flagspace;
 2753 
 2754         flagspace.name = flagspaceObject[RJsonKey::name].toString();
 2755 
 2756         ret << flagspace;
 2757     }
 2758     return ret;
 2759 }
 2760 
 2761 QList<FlagDescription> CutterCore::getAllFlags(QString flagspace)
 2762 {
 2763     CORE_LOCK();
 2764     QList<FlagDescription> ret;
 2765 
 2766     if (!flagspace.isEmpty())
 2767         cmdRaw("fs " + flagspace);
 2768     else
 2769         cmdRaw("fs *");
 2770 
 2771     QJsonArray flagsArray = cmdj("fj").array();
 2772     for (const QJsonValue &value : flagsArray) {
 2773         QJsonObject flagObject = value.toObject();
 2774 
 2775         FlagDescription flag;
 2776 
 2777         flag.offset = flagObject[RJsonKey::offset].toVariant().toULongLong();
 2778         flag.size = flagObject[RJsonKey::size].toVariant().toULongLong();
 2779         flag.name = flagObject[RJsonKey::name].toString();
 2780         flag.realname = flagObject[RJsonKey::realname].toString();
 2781 
 2782         ret << flag;
 2783     }
 2784     return ret;
 2785 }
 2786 
 2787 QList<SectionDescription> CutterCore::getAllSections()
 2788 {
 2789     CORE_LOCK();
 2790     QList<SectionDescription> sections;
 2791 
 2792     QJsonDocument sectionsDoc = cmdj("iSj entropy");
 2793     QJsonObject sectionsObj = sectionsDoc.object();
 2794     QJsonArray sectionsArray = sectionsObj[RJsonKey::sections].toArray();
 2795 
 2796     for (const QJsonValue &value : sectionsArray) {
 2797         QJsonObject sectionObject = value.toObject();
 2798 
 2799         QString name = sectionObject[RJsonKey::name].toString();
 2800         if (name.isEmpty())
 2801             continue;
 2802 
 2803         SectionDescription section;
 2804         section.name = name;
 2805         section.vaddr = sectionObject[RJsonKey::vaddr].toVariant().toULongLong();
 2806         section.vsize = sectionObject[RJsonKey::vsize].toVariant().toULongLong();
 2807         section.paddr = sectionObject[RJsonKey::paddr].toVariant().toULongLong();
 2808         section.size = sectionObject[RJsonKey::size].toVariant().toULongLong();
 2809         section.perm = sectionObject[RJsonKey::perm].toString();
 2810         section.entropy =  sectionObject[RJsonKey::entropy].toString();
 2811 
 2812         sections << section;
 2813     }
 2814     return sections;
 2815 }
 2816 
 2817 QStringList CutterCore::getSectionList()
 2818 {
 2819     CORE_LOCK();
 2820     QStringList ret;
 2821 
 2822     QJsonArray sectionsArray = cmdj("iSj").array();
 2823     for (const QJsonValue &value : sectionsArray) {
 2824         ret << value.toObject()[RJsonKey::name].toString();
 2825     }
 2826     return ret;
 2827 }
 2828 
 2829 QList<SegmentDescription> CutterCore::getAllSegments()
 2830 {
 2831     CORE_LOCK();
 2832     QList<SegmentDescription> ret;
 2833 
 2834     QJsonArray segments = cmdj("iSSj").array();
 2835 
 2836     for (const QJsonValue &value : segments) {
 2837         QJsonObject segmentObject = value.toObject();
 2838 
 2839         QString name = segmentObject[RJsonKey::name].toString();
 2840         if (name.isEmpty())
 2841             continue;
 2842 
 2843         SegmentDescription segment;
 2844         segment.name = name;
 2845         segment.vaddr = segmentObject[RJsonKey::vaddr].toVariant().toULongLong();
 2846         segment.paddr = segmentObject[RJsonKey::paddr].toVariant().toULongLong();
 2847         segment.size = segmentObject[RJsonKey::size].toVariant().toULongLong();
 2848         segment.vsize = segmentObject[RJsonKey::vsize].toVariant().toULongLong();
 2849         segment.perm =  segmentObject[RJsonKey::perm].toString();
 2850 
 2851         ret << segment;
 2852     }
 2853     return ret;
 2854 }
 2855 
 2856 QList<EntrypointDescription> CutterCore::getAllEntrypoint()
 2857 {
 2858     CORE_LOCK();
 2859     QList<EntrypointDescription> ret;
 2860 
 2861     QJsonArray entrypointsArray = cmdj("iej").array();
 2862     for (const QJsonValue &value : entrypointsArray) {
 2863         QJsonObject entrypointObject = value.toObject();
 2864 
 2865         EntrypointDescription entrypoint;
 2866 
 2867         entrypoint.vaddr = entrypointObject[RJsonKey::vaddr].toVariant().toULongLong();
 2868         entrypoint.paddr = entrypointObject[RJsonKey::paddr].toVariant().toULongLong();
 2869         entrypoint.baddr = entrypointObject[RJsonKey::baddr].toVariant().toULongLong();
 2870         entrypoint.laddr = entrypointObject[RJsonKey::laddr].toVariant().toULongLong();
 2871         entrypoint.haddr = entrypointObject[RJsonKey::haddr].toVariant().toULongLong();
 2872         entrypoint.type = entrypointObject[RJsonKey::type].toString();
 2873 
 2874         ret << entrypoint;
 2875     }
 2876     return ret;
 2877 }
 2878 
 2879 QList<BinClassDescription> CutterCore::getAllClassesFromBin()
 2880 {
 2881     CORE_LOCK();
 2882     QList<BinClassDescription> ret;
 2883 
 2884     QJsonArray classesArray = cmdj("icj").array();
 2885     for (const QJsonValue &value : classesArray) {
 2886         QJsonObject classObject = value.toObject();
 2887 
 2888         BinClassDescription cls;
 2889 
 2890         cls.name = classObject[RJsonKey::classname].toString();
 2891         cls.addr = classObject[RJsonKey::addr].toVariant().toULongLong();
 2892         cls.index = classObject[RJsonKey::index].toVariant().toULongLong();
 2893 
 2894         for (const QJsonValue &value2 : classObject[RJsonKey::methods].toArray()) {
 2895             QJsonObject methObject = value2.toObject();
 2896 
 2897             BinClassMethodDescription meth;
 2898 
 2899             meth.name = methObject[RJsonKey::name].toString();
 2900             meth.addr = methObject[RJsonKey::addr].toVariant().toULongLong();
 2901 
 2902             cls.methods << meth;
 2903         }
 2904 
 2905         for (const QJsonValue &value2 : classObject[RJsonKey::fields].toArray()) {
 2906             QJsonObject fieldObject = value2.toObject();
 2907 
 2908             BinClassFieldDescription field;
 2909 
 2910             field.name = fieldObject[RJsonKey::name].toString();
 2911             field.addr = fieldObject[RJsonKey::addr].toVariant().toULongLong();
 2912 
 2913             cls.fields << field;
 2914         }
 2915 
 2916         ret << cls;
 2917     }
 2918     return ret;
 2919 }
 2920 
 2921 QList<BinClassDescription> CutterCore::getAllClassesFromFlags()
 2922 {
 2923     static const QRegularExpression classFlagRegExp("^class\\.(.*)$");
 2924     static const QRegularExpression methodFlagRegExp("^method\\.([^\\.]*)\\.(.*)$");
 2925 
 2926     CORE_LOCK();
 2927     QList<BinClassDescription> ret;
 2928     QMap<QString, BinClassDescription *> classesCache;
 2929 
 2930     QJsonArray flagsArray = cmdj("fj@F:classes").array();
 2931     for (const QJsonValue &value : flagsArray) {
 2932         QJsonObject flagObject = value.toObject();
 2933 
 2934         QString flagName = flagObject[RJsonKey::name].toString();
 2935 
 2936         QRegularExpressionMatch match = classFlagRegExp.match(flagName);
 2937         if (match.hasMatch()) {
 2938             QString className = match.captured(1);
 2939             BinClassDescription *desc = nullptr;
 2940             auto it = classesCache.find(className);
 2941             if (it == classesCache.end()) {
 2942                 BinClassDescription cls = {};
 2943                 ret << cls;
 2944                 desc = &ret.last();
 2945                 classesCache[className] = desc;
 2946             } else {
 2947                 desc = it.value();
 2948             }
 2949             desc->name = match.captured(1);
 2950             desc->addr = flagObject[RJsonKey::offset].toVariant().toULongLong();
 2951             desc->index = RVA_INVALID;
 2952             continue;
 2953         }
 2954 
 2955         match = methodFlagRegExp.match(flagName);
 2956         if (match.hasMatch()) {
 2957             QString className = match.captured(1);
 2958             BinClassDescription *classDesc = nullptr;
 2959             auto it = classesCache.find(className);
 2960             if (it == classesCache.end()) {
 2961                 // add a new stub class, will be replaced if class flag comes after it
 2962                 BinClassDescription cls;
 2963                 cls.name = tr("Unknown (%1)").arg(className);
 2964                 cls.addr = RVA_INVALID;
 2965                 cls.index = 0;
 2966                 ret << cls;
 2967                 classDesc = &ret.last();
 2968                 classesCache[className] = classDesc;
 2969             } else {
 2970                 classDesc = it.value();
 2971             }
 2972 
 2973             BinClassMethodDescription meth;
 2974             meth.name = match.captured(2);
 2975             meth.addr = flagObject[RJsonKey::offset].toVariant().toULongLong();
 2976             classDesc->methods << meth;
 2977             continue;
 2978         }
 2979     }
 2980     return ret;
 2981 }
 2982 
 2983 QList<QString> CutterCore::getAllAnalClasses(bool sorted)
 2984 {
 2985     CORE_LOCK();
 2986     QList<QString> ret;
 2987 
 2988     SdbListPtr l = makeSdbListPtr(r_anal_class_get_all(core->anal, sorted));
 2989     if (!l) {
 2990         return ret;
 2991     }
 2992     ret.reserve(static_cast<int>(l->length));
 2993 
 2994     SdbListIter *it;
 2995     void *entry;
 2996     ls_foreach(l, it, entry) {
 2997         auto kv = reinterpret_cast<SdbKv *>(entry);
 2998         ret.append(QString::fromUtf8(reinterpret_cast<const char *>(kv->base.key)));
 2999     }
 3000 
 3001     return ret;
 3002 }
 3003 
 3004 QList<AnalMethodDescription> CutterCore::getAnalClassMethods(const QString &cls)
 3005 {
 3006     CORE_LOCK();
 3007     QList<AnalMethodDescription> ret;
 3008 
 3009     RVector *meths = r_anal_class_method_get_all(core->anal, cls.toUtf8().constData());
 3010     if (!meths) {
 3011         return ret;
 3012     }
 3013 
 3014     ret.reserve(static_cast<int>(meths->len));
 3015     RAnalMethod *meth;
 3016     CutterRVectorForeach(meths, meth, RAnalMethod) {
 3017         AnalMethodDescription desc;
 3018         desc.name = QString::fromUtf8(meth->name);
 3019         desc.addr = meth->addr;
 3020         desc.vtableOffset = meth->vtable_offset;
 3021         ret.append(desc);
 3022     }
 3023     r_vector_free(meths);
 3024 
 3025     return ret;
 3026 }
 3027 
 3028 QList<AnalBaseClassDescription> CutterCore::getAnalClassBaseClasses(const QString &cls)
 3029 {
 3030     CORE_LOCK();
 3031     QList<AnalBaseClassDescription> ret;
 3032 
 3033     RVector *bases = r_anal_class_base_get_all(core->anal, cls.toUtf8().constData());
 3034     if (!bases) {
 3035         return ret;
 3036     }
 3037 
 3038     ret.reserve(static_cast<int>(bases->len));
 3039     RAnalBaseClass *base;
 3040     CutterRVectorForeach(bases, base, RAnalBaseClass) {
 3041         AnalBaseClassDescription desc;
 3042         desc.id = QString::fromUtf8(base->id);
 3043         desc.offset = base->offset;
 3044         desc.className = QString::fromUtf8(base->class_name);
 3045         ret.append(desc);
 3046     }
 3047     r_vector_free(bases);
 3048 
 3049     return ret;
 3050 }
 3051 
 3052 QList<AnalVTableDescription> CutterCore::getAnalClassVTables(const QString &cls)
 3053 {
 3054     CORE_LOCK();
 3055     QList<AnalVTableDescription> acVtables;
 3056 
 3057     RVector *vtables = r_anal_class_vtable_get_all(core->anal, cls.toUtf8().constData());
 3058     if (!vtables) {
 3059         return acVtables;
 3060     }
 3061 
 3062     acVtables.reserve(static_cast<int>(vtables->len));
 3063     RAnalVTable *vtable;
 3064     CutterRVectorForeach(vtables, vtable, RAnalVTable) {
 3065         AnalVTableDescription desc;
 3066         desc.id = QString::fromUtf8(vtable->id);
 3067         desc.offset = vtable->offset;
 3068         desc.addr = vtable->addr;
 3069         acVtables.append(desc);
 3070     }
 3071     r_vector_free(vtables);
 3072 
 3073     return acVtables;
 3074 }
 3075 
 3076 void CutterCore::createNewClass(const QString &cls)
 3077 {
 3078     CORE_LOCK();
 3079     r_anal_class_create(core->anal, cls.toUtf8().constData());
 3080 }
 3081 
 3082 void CutterCore::renameClass(const QString &oldName, const QString &newName)
 3083 {
 3084     CORE_LOCK();
 3085     r_anal_class_rename(core->anal, oldName.toUtf8().constData(), newName.toUtf8().constData());
 3086 }
 3087 
 3088 void CutterCore::deleteClass(const QString &cls)
 3089 {
 3090     CORE_LOCK();
 3091     r_anal_class_delete(core->anal, cls.toUtf8().constData());
 3092 }
 3093 
 3094 bool CutterCore::getAnalMethod(const QString &cls, const QString &meth, AnalMethodDescription *desc)
 3095 {
 3096     CORE_LOCK();
 3097     RAnalMethod analMeth;
 3098     if (r_anal_class_method_get(core->anal, cls.toUtf8().constData(), meth.toUtf8().constData(), &analMeth) != R_ANAL_CLASS_ERR_SUCCESS) {
 3099         return false;
 3100     }
 3101     desc->name = QString::fromUtf8(analMeth.name);
 3102     desc->addr = analMeth.addr;
 3103     desc->vtableOffset = analMeth.vtable_offset;
 3104     r_anal_class_method_fini(&analMeth);
 3105     return true;
 3106 }
 3107 
 3108 void CutterCore::setAnalMethod(const QString &className, const AnalMethodDescription &meth)
 3109 {
 3110     CORE_LOCK();
 3111     RAnalMethod analMeth;
 3112     analMeth.name = strdup (meth.name.toUtf8().constData());
 3113     analMeth.addr = meth.addr;
 3114     analMeth.vtable_offset = meth.vtableOffset;
 3115     r_anal_class_method_set(core->anal, className.toUtf8().constData(), &analMeth);
 3116     r_anal_class_method_fini(&analMeth);
 3117 }
 3118 
 3119 void CutterCore::renameAnalMethod(const QString &className, const QString &oldMethodName, const QString &newMethodName)
 3120 {
 3121     CORE_LOCK();
 3122     r_anal_class_method_rename(core->anal, className.toUtf8().constData(), oldMethodName.toUtf8().constData(), newMethodName.toUtf8().constData());
 3123 }
 3124 
 3125 QList<ResourcesDescription> CutterCore::getAllResources()
 3126 {
 3127     CORE_LOCK();
 3128     QList<ResourcesDescription> resources;
 3129 
 3130     QJsonArray resourcesArray = cmdj("iRj").array();
 3131     for (const QJsonValue &value : resourcesArray) {
 3132         QJsonObject resourceObject = value.toObject();
 3133 
 3134         ResourcesDescription res;
 3135 
 3136         res.name = resourceObject[RJsonKey::name].toString();
 3137         res.vaddr = resourceObject[RJsonKey::vaddr].toVariant().toULongLong();
 3138         res.index = resourceObject[RJsonKey::index].toVariant().toULongLong();
 3139         res.type = resourceObject[RJsonKey::type].toString();
 3140         res.size = resourceObject[RJsonKey::size].toVariant().toULongLong();
 3141         res.lang = resourceObject[RJsonKey::lang].toString();
 3142 
 3143         resources << res;
 3144     }
 3145     return resources;
 3146 }
 3147 
 3148 QList<VTableDescription> CutterCore::getAllVTables()
 3149 {
 3150     CORE_LOCK();
 3151     QList<VTableDescription> vtables;
 3152 
 3153     QJsonArray vTablesArray = cmdj("avj").array();
 3154     for (const QJsonValue &vTableValue : vTablesArray) {
 3155         QJsonObject vTableObject = vTableValue.toObject();
 3156 
 3157         VTableDescription res;
 3158 
 3159         res.addr = vTableObject[RJsonKey::offset].toVariant().toULongLong();
 3160         QJsonArray methodArray = vTableObject[RJsonKey::methods].toArray();
 3161 
 3162         for (const QJsonValue &methodValue : methodArray) {
 3163             QJsonObject methodObject = methodValue.toObject();
 3164 
 3165             BinClassMethodDescription method;
 3166 
 3167             method.addr = methodObject[RJsonKey::offset].toVariant().toULongLong();
 3168             method.name = methodObject[RJsonKey::name].toString();
 3169 
 3170             res.methods << method;
 3171         }
 3172 
 3173         vtables << res;
 3174     }
 3175     return vtables;
 3176 }
 3177 
 3178 QList<TypeDescription> CutterCore::getAllTypes()
 3179 {
 3180     QList<TypeDescription> types;
 3181 
 3182     types.append(getAllPrimitiveTypes());
 3183     types.append(getAllUnions());
 3184     types.append(getAllStructs());
 3185     types.append(getAllEnums());
 3186     types.append(getAllTypedefs());
 3187 
 3188     return types;
 3189 }
 3190 
 3191 QList<TypeDescription> CutterCore::getAllPrimitiveTypes()
 3192 {
 3193     CORE_LOCK();
 3194     QList<TypeDescription> primitiveTypes;
 3195 
 3196     QJsonArray typesArray = cmdj("tj").array();
 3197     for (const QJsonValue &value : typesArray) {
 3198         QJsonObject typeObject = value.toObject();
 3199 
 3200         TypeDescription exp;
 3201 
 3202         exp.type = typeObject[RJsonKey::type].toString();
 3203         exp.size = typeObject[RJsonKey::size].toVariant().toULongLong();
 3204         exp.format = typeObject[RJsonKey::format].toString();
 3205         exp.category = tr("Primitive");
 3206         primitiveTypes << exp;
 3207     }
 3208 
 3209     return primitiveTypes;
 3210 }
 3211 
 3212 QList<TypeDescription> CutterCore::getAllUnions()
 3213 {
 3214     CORE_LOCK();
 3215     QList<TypeDescription> unions;
 3216 
 3217     QJsonArray typesArray = cmdj("tuj").array();
 3218     for (const QJsonValue value: typesArray) {
 3219         QJsonObject typeObject = value.toObject();
 3220 
 3221         TypeDescription exp;
 3222 
 3223         exp.type = typeObject[RJsonKey::type].toString();
 3224         exp.size = typeObject[RJsonKey::size].toVariant().toULongLong();
 3225         exp.category = "Union";
 3226         unions << exp;
 3227     }
 3228 
 3229     return unions;
 3230 }
 3231 
 3232 QList<TypeDescription> CutterCore::getAllStructs()
 3233 {
 3234     CORE_LOCK();
 3235     QList<TypeDescription> structs;
 3236 
 3237     QJsonArray typesArray = cmdj("tsj").array();
 3238     for (const QJsonValue value: typesArray) {
 3239         QJsonObject typeObject = value.toObject();
 3240 
 3241         TypeDescription exp;
 3242 
 3243         exp.type = typeObject[RJsonKey::type].toString();
 3244         exp.size = typeObject[RJsonKey::size].toVariant().toULongLong();
 3245         exp.category = "Struct";
 3246         structs << exp;
 3247     }
 3248 
 3249     return structs;
 3250 }
 3251 
 3252 QList<TypeDescription> CutterCore::getAllEnums()
 3253 {
 3254     CORE_LOCK();
 3255     QList<TypeDescription> enums;
 3256 
 3257     QJsonObject typesObject = cmdj("tej").object();
 3258     for (QString key: typesObject.keys()) {
 3259         TypeDescription exp;
 3260         exp.type = key;
 3261         exp.size = 0;
 3262         exp.category = "Enum";
 3263         enums << exp;
 3264     }
 3265 
 3266     return enums;
 3267 }
 3268 
 3269 QList<TypeDescription> CutterCore::getAllTypedefs()
 3270 {
 3271     CORE_LOCK();
 3272     QList<TypeDescription> typeDefs;
 3273 
 3274     QJsonObject typesObject = cmdj("ttj").object();
 3275     for (QString key: typesObject.keys()) {
 3276         TypeDescription exp;
 3277         exp.type = key;
 3278         exp.size = 0;
 3279         exp.category = "Typedef";
 3280         typeDefs << exp;
 3281     }
 3282 
 3283     return typeDefs;
 3284 }
 3285 
 3286 QString CutterCore::addTypes(const char *str)
 3287 {
 3288     CORE_LOCK();
 3289     char *error_msg = nullptr;
 3290     char *parsed = r_parse_c_string(core->anal, str, &error_msg);
 3291     QString error;
 3292 
 3293     if (!parsed) {
 3294          if (error_msg) {
 3295              error = error_msg;
 3296              r_mem_free(error_msg);
 3297          }
 3298          return error;
 3299     }
 3300 
 3301     r_anal_save_parsed_type(core->anal, parsed);
 3302     r_mem_free(parsed);
 3303 
 3304     if (error_msg) {
 3305         error = error_msg;
 3306         r_mem_free(error_msg);
 3307     }
 3308 
 3309     return error;
 3310 }
 3311 
 3312 QString CutterCore::getTypeAsC(QString name, QString category)
 3313 {
 3314     CORE_LOCK();
 3315     QString output = "Failed to fetch the output.";
 3316     if (name.isEmpty() || category.isEmpty()) {
 3317         return output;
 3318     }
 3319     QString typeName = sanitizeStringForCommand(name);
 3320     if (category == "Struct") {
 3321         output = cmdRaw(QString("tsc %1").arg(typeName));
 3322     } else if (category == "Union") {
 3323         output = cmdRaw(QString("tuc %1").arg(typeName));
 3324     } else if(category == "Enum") {
 3325         output = cmdRaw(QString("tec %1").arg(typeName));
 3326     } else if(category == "Typedef") {
 3327         output = cmdRaw(QString("ttc %1").arg(typeName));
 3328     }
 3329     return output;
 3330 }
 3331 
 3332 bool CutterCore::isAddressMapped(RVA addr)
 3333 {
 3334     // If value returned by "om. @ addr" is empty means that address is not mapped
 3335     return !Core()->cmdRawAt(QString("om."), addr).isEmpty();
 3336 }
 3337 
 3338 QList<SearchDescription> CutterCore::getAllSearch(QString search_for, QString space)
 3339 {
 3340     CORE_LOCK();
 3341     QList<SearchDescription> searchRef;
 3342 
 3343     QJsonArray searchArray = cmdj(space + QString(" ") + search_for).array();
 3344 
 3345     if (space == "/Rj") {
 3346         for (const QJsonValue &value : searchArray) {
 3347             QJsonObject searchObject = value.toObject();
 3348 
 3349             SearchDescription exp;
 3350 
 3351             exp.code.clear();
 3352             for (const QJsonValue &value2 : searchObject[RJsonKey::opcodes].toArray()) {
 3353                 QJsonObject gadget = value2.toObject();
 3354                 exp.code += gadget[RJsonKey::opcode].toString() + ";  ";
 3355             }
 3356 
 3357             exp.offset =
 3358                 searchObject[RJsonKey::opcodes].toArray().first().toObject()[RJsonKey::offset].toVariant().toULongLong();
 3359             exp.size = searchObject[RJsonKey::size].toVariant().toULongLong();
 3360 
 3361             searchRef << exp;
 3362         }
 3363     } else {
 3364         for (const QJsonValue &value : searchArray) {
 3365             QJsonObject searchObject = value.toObject();
 3366 
 3367             SearchDescription exp;
 3368 
 3369             exp.offset = searchObject[RJsonKey::offset].toVariant().toULongLong();
 3370             exp.size = searchObject[RJsonKey::len].toVariant().toULongLong();
 3371             exp.code = searchObject[RJsonKey::code].toString();
 3372             exp.data = searchObject[RJsonKey::data].toString();
 3373 
 3374             searchRef << exp;
 3375         }
 3376     }
 3377     return searchRef;
 3378 }
 3379 
 3380 BlockStatistics CutterCore::getBlockStatistics(unsigned int blocksCount)
 3381 {
 3382     BlockStatistics blockStats;
 3383     if (blocksCount == 0) {
 3384         blockStats.from = blockStats.to = blockStats.blocksize = 0;
 3385         return blockStats;
 3386     }
 3387 
 3388     QJsonObject statsObj = cmdj("p-j " + QString::number(blocksCount)).object();
 3389 
 3390     blockStats.from = statsObj[RJsonKey::from].toVariant().toULongLong();
 3391     blockStats.to = statsObj[RJsonKey::to].toVariant().toULongLong();
 3392     blockStats.blocksize = statsObj[RJsonKey::blocksize].toVariant().toULongLong();
 3393 
 3394     QJsonArray blocksArray = statsObj[RJsonKey::blocks].toArray();
 3395 
 3396     for (const QJsonValue &value : blocksArray) {
 3397         QJsonObject blockObj = value.toObject();
 3398 
 3399         BlockDescription block;
 3400 
 3401         block.addr = blockObj[RJsonKey::offset].toVariant().toULongLong();
 3402         block.size = blockObj[RJsonKey::size].toVariant().toULongLong();
 3403         block.flags = blockObj[RJsonKey::flags].toInt(0);
 3404         block.functions = blockObj[RJsonKey::functions].toInt(0);
 3405         block.inFunctions = blockObj[RJsonKey::in_functions].toInt(0);
 3406         block.comments = blockObj[RJsonKey::comments].toInt(0);
 3407         block.symbols = blockObj[RJsonKey::symbols].toInt(0);
 3408         block.strings = blockObj[RJsonKey::strings].toInt(0);
 3409 
 3410         block.rwx = 0;
 3411         QString rwxStr = blockObj[RJsonKey::rwx].toString();
 3412         if (rwxStr.length() == 3) {
 3413             if (rwxStr[0] == 'r') {
 3414                 block.rwx |= (1 << 0);
 3415             }
 3416             if (rwxStr[1] == 'w') {
 3417                 block.rwx |= (1 << 1);
 3418             }
 3419             if (rwxStr[2] == 'x') {
 3420                 block.rwx |= (1 << 2);
 3421             }
 3422         }
 3423 
 3424         blockStats.blocks << block;
 3425     }
 3426 
 3427     return blockStats;
 3428 }
 3429 
 3430 QList<XrefDescription> CutterCore::getXRefs(RVA addr, bool to, bool whole_function,
 3431                                             const QString &filterType)
 3432 {
 3433     QList<XrefDescription> xrefList = QList<XrefDescription>();
 3434 
 3435     QJsonArray xrefsArray;
 3436 
 3437     if (to) {
 3438         xrefsArray = cmdj("axtj@" + QString::number(addr)).array();
 3439     } else {
 3440         xrefsArray = cmdj("axfj@" + QString::number(addr)).array();
 3441     }
 3442 
 3443     for (const QJsonValue &value : xrefsArray) {
 3444         QJsonObject xrefObject = value.toObject();
 3445 
 3446         XrefDescription xref;
 3447 
 3448         xref.type = xrefObject[RJsonKey::type].toString();
 3449 
 3450         if (!filterType.isNull() && filterType != xref.type)
 3451             continue;
 3452 
 3453         xref.from = xrefObject[RJsonKey::from].toVariant().toULongLong();
 3454         if (!to) {
 3455             xref.from_str = RAddressString(xref.from);
 3456         } else {
 3457             QString fcn = xrefObject[RJsonKey::fcn_name].toString();
 3458             if (!fcn.isEmpty()) {
 3459                 RVA fcnAddr = xrefObject[RJsonKey::fcn_addr].toVariant().toULongLong();
 3460                 xref.from_str = fcn + " + 0x" + QString::number(xref.from - fcnAddr, 16);
 3461             } else {
 3462                 xref.from_str = RAddressString(xref.from);
 3463             }
 3464         }
 3465 
 3466         if (!whole_function && !to && xref.from != addr) {
 3467             continue;
 3468         }
 3469 
 3470         if (to && !xrefObject.contains(RJsonKey::to)) {
 3471             xref.to = addr;
 3472         } else {
 3473             xref.to = xrefObject[RJsonKey::to].toVariant().toULongLong();
 3474         }
 3475         xref.to_str = Core()->cmdRaw(QString("fd %1").arg(xref.to)).trimmed();
 3476 
 3477         xrefList << xref;
 3478     }
 3479 
 3480     return xrefList;
 3481 }
 3482 
 3483 void CutterCore::addFlag(RVA offset, QString name, RVA size)
 3484 {
 3485     name = sanitizeStringForCommand(name);
 3486     cmdRawAt(QString("f %1 %2").arg(name).arg(size), offset);
 3487     emit flagsChanged();
 3488 }
 3489 
 3490 /**
 3491  * @brief Gets all the flags present at a specific address
 3492  * @param addr The address to be checked
 3493  * @return String containing all the flags which are comma-separated
 3494  */
 3495 QString CutterCore::listFlagsAsStringAt(RVA addr)
 3496 {
 3497     CORE_LOCK();
 3498     char *flagList = r_flag_get_liststr (core->flags, addr);
 3499     QString result = fromOwnedCharPtr(flagList);
 3500     return result;
 3501 }
 3502 
 3503 QString CutterCore::nearestFlag(RVA offset, RVA *flagOffsetOut)
 3504 {
 3505     auto r = cmdj(QString("fdj @") + QString::number(offset)).object();
 3506     QString name = r.value("name").toString();
 3507     if (flagOffsetOut) {
 3508         int queryOffset = r.value("offset").toInt(0);
 3509         *flagOffsetOut = offset  + static_cast<RVA>(-queryOffset);
 3510     }
 3511     return name;
 3512 }
 3513 
 3514 void CutterCore::handleREvent(int type, void *data)
 3515 {
 3516     switch (type) {
 3517     case R_EVENT_CLASS_NEW: {
 3518         auto ev = reinterpret_cast<REventClass *>(data);
 3519         emit classNew(QString::fromUtf8(ev->name));
 3520         break;
 3521     }
 3522     case R_EVENT_CLASS_DEL: {
 3523         auto ev = reinterpret_cast<REventClass *>(data);
 3524         emit classDeleted(QString::fromUtf8(ev->name));
 3525         break;
 3526     }
 3527     case R_EVENT_CLASS_RENAME: {
 3528         auto ev = reinterpret_cast<REventClassRename *>(data);
 3529         emit classRenamed(QString::fromUtf8(ev->name_old), QString::fromUtf8(ev->name_new));
 3530         break;
 3531     }
 3532     case R_EVENT_CLASS_ATTR_SET: {
 3533         auto ev = reinterpret_cast<REventClassAttrSet *>(data);
 3534         emit classAttrsChanged(QString::fromUtf8(ev->attr.class_name));
 3535         break;
 3536     }
 3537     case R_EVENT_CLASS_ATTR_DEL: {
 3538         auto ev = reinterpret_cast<REventClassAttr *>(data);
 3539         emit classAttrsChanged(QString::fromUtf8(ev->class_name));
 3540         break;
 3541     }
 3542     case R_EVENT_CLASS_ATTR_RENAME: {
 3543         auto ev = reinterpret_cast<REventClassAttrRename *>(data);
 3544         emit classAttrsChanged(QString::fromUtf8(ev->attr.class_name));
 3545         break;
 3546     }
 3547     case R_EVENT_DEBUG_PROCESS_FINISHED: {
 3548         auto ev = reinterpret_cast<REventDebugProcessFinished*>(data);
 3549         emit debugProcessFinished(ev->pid);
 3550         break;
 3551     }
 3552     default:
 3553         break;
 3554     }
 3555 }
 3556 
 3557 void CutterCore::triggerFlagsChanged()
 3558 {
 3559     emit flagsChanged();
 3560 }
 3561 
 3562 void CutterCore::triggerVarsChanged()
 3563 {
 3564     emit varsChanged();
 3565 }
 3566 
 3567 void CutterCore::triggerFunctionRenamed(const QString &prevName, const QString &newName)
 3568 {
 3569     emit functionRenamed(prevName, newName);
 3570 }
 3571 
 3572 void CutterCore::loadPDB(const QString &file)
 3573 {
 3574     cmdRaw("idp " + sanitizeStringForCommand(file));
 3575 }
 3576 
 3577 void CutterCore::openProject(const QString &name)
 3578 {
 3579     cmdRaw("Po " + name);
 3580 
 3581     QString notes = QString::fromUtf8(QByteArray::fromBase64(cmdRaw("Pnj").toUtf8()));
 3582 }
 3583 
 3584 void CutterCore::saveProject(const QString &name)
 3585 {
 3586     const QString &rv = cmdRaw("Ps " + name.trimmed()).trimmed();
 3587     const bool ok = rv == name.trimmed();
 3588     cmdRaw(QString("Pnj %1").arg(QString(notes.toUtf8().toBase64())));
 3589     emit projectSaved(ok, name);
 3590 }
 3591 
 3592 void CutterCore::deleteProject(const QString &name)
 3593 {
 3594     cmdRaw("Pd " + name);
 3595 }
 3596 
 3597 bool CutterCore::isProjectNameValid(const QString &name)
 3598 {
 3599     // see is_valid_project_name() in libr/core/project.
 3600 
 3601     QString pattern(R"(^[a-zA-Z0-9\\\._:-]{1,}$)");
 3602     // The below construct mimics the behaviour of QRegexP::exactMatch(), which was here before
 3603     static const QRegularExpression regexp("\\A(?:" + pattern + ")\\z");
 3604     return regexp.match(name).hasMatch() && !name.endsWith(".zip") ;
 3605 }
 3606 
 3607 QList<DisassemblyLine> CutterCore::disassembleLines(RVA offset, int lines)
 3608 {
 3609     QJsonArray array = cmdj(QString("pdJ ") + QString::number(lines) + QString(" @ ") + QString::number(
 3610                                 offset)).array();
 3611     QList<DisassemblyLine> r;
 3612 
 3613     for (const QJsonValueRef &value : array) {
 3614         QJsonObject object = value.toObject();
 3615         DisassemblyLine line;
 3616         line.offset = object[RJsonKey::offset].toVariant().toULongLong();
 3617         line.text = ansiEscapeToHtml(object[RJsonKey::text].toString());
 3618         const auto& arrow = object[RJsonKey::arrow];
 3619         line.arrow = arrow.isNull()
 3620                      ? RVA_INVALID
 3621                      : arrow.toVariant().toULongLong();
 3622         r << line;
 3623     }
 3624 
 3625     return r;
 3626 }
 3627 
 3628 
 3629 /**
 3630  * @brief return hexdump of <size> from an <offset> by a given formats
 3631  * @param address - the address from which to print the hexdump
 3632  * @param size - number of bytes to print 
 3633  * @param format - the type of hexdump (qwords, words. decimal, etc)
 3634  */
 3635 QString CutterCore::hexdump(RVA address, int size, HexdumpFormats format)
 3636 {
 3637     QString command = "px";
 3638     switch (format) {
 3639     case HexdumpFormats::Normal:
 3640         break;
 3641     case HexdumpFormats::Half:
 3642         command += "h";
 3643         break;
 3644     case HexdumpFormats::Word:
 3645         command += "w";
 3646         break;
 3647     case HexdumpFormats::Quad:
 3648         command += "q";
 3649         break;
 3650     case HexdumpFormats::Signed:
 3651         command += "d";
 3652         break;
 3653     case HexdumpFormats::Octal:
 3654         command += "o";
 3655         break;
 3656     }
 3657 
 3658     return cmdRawAt(QString("%1 %2")
 3659                         .arg(command)
 3660                         .arg(size),
 3661                         address);
 3662 }
 3663 
 3664 QByteArray CutterCore::hexStringToBytes(const QString &hex)
 3665 {
 3666     QByteArray hexChars = hex.toUtf8();
 3667     QByteArray bytes;
 3668     bytes.reserve(hexChars.length() / 2);
 3669     int size = r_hex_str2bin(hexChars.constData(), reinterpret_cast<ut8 *>(bytes.data()));
 3670     bytes.resize(size);
 3671     return bytes;
 3672 }
 3673 
 3674 QString CutterCore::bytesToHexString(const QByteArray &bytes)
 3675 {
 3676     QByteArray hex;
 3677     hex.resize(bytes.length() * 2);
 3678     r_hex_bin2str(reinterpret_cast<const ut8 *>(bytes.constData()), bytes.size(), hex.data());
 3679     return QString::fromUtf8(hex);
 3680 }
 3681 
 3682 void CutterCore::loadScript(const QString &scriptname)
 3683 {
 3684     {
 3685         CORE_LOCK();
 3686         r_core_cmd_file(core, scriptname.toUtf8().constData());
 3687     }
 3688     triggerRefreshAll();
 3689 }
 3690 
 3691 QString CutterCore::getVersionInformation()
 3692 {
 3693     int i;
 3694     QString versionInfo;
 3695     struct vcs_t {
 3696         const char *name;
 3697         const char *(*callback)();
 3698     } vcs[] = {
 3699         { "r_anal", &r_anal_version },
 3700         { "r_lib", &r_lib_version },
 3701         { "r_egg", &r_egg_version },
 3702         { "r_asm", &r_asm_version },
 3703         { "r_bin", &r_bin_version },
 3704         { "r_cons", &r_cons_version },
 3705         { "r_flag", &r_flag_version },
 3706         { "r_core", &r_core_version },
 3707         { "r_crypto", &r_crypto_version },
 3708         { "r_bp", &r_bp_version },
 3709         { "r_debug", &r_debug_version },
 3710         { "r_hash", &r_hash_version },
 3711         { "r_fs", &r_fs_version },
 3712         { "r_io", &r_io_version },
 3713 #if !USE_LIB_MAGIC
 3714         { "r_magic", &r_magic_version },
 3715 #endif
 3716         { "r_parse", &r_parse_version },
 3717         { "r_reg", &r_reg_version },
 3718         { "r_sign", &r_sign_version },
 3719         { "r_search", &r_search_version },
 3720         { "r_syscall", &r_syscall_version },
 3721         { "r_util", &r_util_version },
 3722         /* ... */
 3723         {NULL, NULL}
 3724     };
 3725     versionInfo.append(QString("%1 r2\n").arg(R2_GITTAP));
 3726     for (i = 0; vcs[i].name; i++) {
 3727         struct vcs_t *v = &vcs[i];
 3728         const char *name = v->callback ();
 3729         versionInfo.append(QString("%1 %2\n").arg(name, v->name));
 3730     }
 3731     return versionInfo;
 3732 }
 3733 
 3734 QJsonArray CutterCore::getOpenedFiles()
 3735 {
 3736     QJsonDocument files = cmdj("oj");
 3737     return files.array();
 3738 }
 3739 
 3740 QList<QString> CutterCore::getColorThemes()
 3741 {
 3742     QList<QString> r;
 3743     QJsonDocument themes = cmdj("ecoj");
 3744     for (const QJsonValue &s : themes.array()) {
 3745         r << s.toString();
 3746     }
 3747     return r;
 3748 }
 3749 
 3750 QString CutterCore::ansiEscapeToHtml(const QString &text)
 3751 {
 3752     int len;
 3753     char *html = r_cons_html_filter(text.toUtf8().constData(), &len);
 3754     if (!html) {
 3755         return QString();
 3756     }
 3757     QString r = QString::fromUtf8(html, len);
 3758     r_mem_free(html);
 3759     return r;
 3760 }
 3761 
 3762 BasicBlockHighlighter* CutterCore::getBBHighlighter()
 3763 {
 3764     return bbHighlighter;
 3765 }
 3766 
 3767 BasicInstructionHighlighter* CutterCore::getBIHighlighter()
 3768 {
 3769     return &biHighlighter;
 3770 }
 3771 
 3772 void CutterCore::setIOCache(bool enabled)
 3773 {
 3774     setConfig("io.cache", enabled);
 3775     this->iocache = enabled;
 3776     emit ioCacheChanged(enabled);
 3777 }
 3778 
 3779 bool CutterCore::isIOCacheEnabled() const
 3780 {
 3781     return iocache;
 3782 }
 3783 
 3784 void CutterCore::commitWriteCache()
 3785 {
 3786     if (!isWriteModeEnabled()) {
 3787         setWriteMode (true);
 3788         cmdRaw("wci");
 3789         cmdRaw("oo");
 3790     } else {
 3791         cmdRaw("wci");
 3792     }
 3793 }
 3794 
 3795 // Enable or disable write-mode. Avoid unecessary changes if not need.
 3796 void CutterCore::setWriteMode(bool enabled)
 3797 {
 3798     bool writeModeState = isWriteModeEnabled();
 3799 
 3800     if (writeModeState == enabled) {
 3801         // New mode is the same as current. Do nothing.
 3802         return;
 3803     }
 3804     
 3805     // Change from read-only to write-mode
 3806     if (enabled && !writeModeState) {
 3807         cmdRaw("oo+");
 3808     // Change from write-mode to read-only
 3809     } else {
 3810         cmdRaw("oo");
 3811     }
 3812     writeModeChanged (enabled);
 3813 }
 3814 
 3815 bool CutterCore::isWriteModeEnabled()
 3816 {
 3817     using namespace std;
 3818     QJsonArray ans = cmdj("oj").array();
 3819     return find_if(begin(ans), end(ans), [](const QJsonValue &v) {
 3820         return v.toObject().value("raised").toBool();
 3821     })->toObject().value("writable").toBool();
 3822 }
 3823 
 3824 /**
 3825  * @brief get a compact disassembly preview for tooltips
 3826  * @param address - the address from which to print the disassembly
 3827  * @param num_of_lines - number of instructions to print 
 3828  */
 3829 QStringList CutterCore::getDisassemblyPreview(RVA address, int num_of_lines)
 3830 {
 3831      QList<DisassemblyLine> disassemblyLines;
 3832         {
 3833             // temporarily simplify the disasm output to get it colorful and simple to read
 3834             TempConfig tempConfig;
 3835             tempConfig
 3836                 .set("scr.color", COLOR_MODE_16M)
 3837                 .set("asm.lines", false)
 3838                 .set("asm.var", false)
 3839                 .set("asm.comments", false)
 3840                 .set("asm.bytes", false)
 3841                 .set("asm.lines.fcn", false)
 3842                 .set("asm.lines.out", false)
 3843                 .set("asm.lines.bb", false)
 3844                 .set("asm.bb.line", false);
 3845 
 3846             disassemblyLines = disassembleLines(address, num_of_lines + 1);
 3847         }
 3848         QStringList disasmPreview;
 3849         for (const DisassemblyLine &line : disassemblyLines) {
 3850             disasmPreview << line.text;
 3851             if (disasmPreview.length() >= num_of_lines) {
 3852                 disasmPreview << "...";
 3853                 break;
 3854             }
 3855         }
 3856         if (!disasmPreview.isEmpty()) {
 3857             return disasmPreview;
 3858         } else {
 3859             return QStringList();
 3860         }
 3861 }
 3862 
 3863 /**
 3864  * @brief get a compact hexdump preview for tooltips
 3865  * @param address - the address from which to print the hexdump
 3866  * @param size - number of bytes to print 
 3867  */
 3868 QString CutterCore::getHexdumpPreview(RVA address, int size)
 3869 {     
 3870     // temporarily simplify the disasm output to get it colorful and simple to read
 3871     TempConfig tempConfig;
 3872     tempConfig
 3873         .set("scr.color", COLOR_MODE_16M)
 3874         .set("asm.offset", true)
 3875         .set("hex.header", false)
 3876         .set("hex.cols", 16);
 3877     return ansiEscapeToHtml(hexdump(address, size, HexdumpFormats::Normal)).replace(QLatin1Char('\n'), "<br>");
 3878 }
 3879 
 3880 QByteArray CutterCore::ioRead(RVA addr, int len)
 3881 {
 3882     CORE_LOCK();
 3883 
 3884     QByteArray array;
 3885 
 3886     if (len <= 0)
 3887         return array;
 3888 
 3889     /* Zero-copy */
 3890     array.resize(len);
 3891     if (!r_io_read_at(core->io, addr, (uint8_t *)array.data(), len)) {
 3892         qWarning() << "Can't read data" << addr << len;
 3893         array.fill(0xff);
 3894     }
 3895 
 3896     return  array;
 3897 }