diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ba6691c9..9b606132 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -5,6 +5,7 @@ set(SOURCES Main.cpp core/Cutter.cpp core/CutterJson.cpp + core/RizinCpp.cpp dialogs/EditStringDialog.cpp dialogs/WriteCommandsDialogs.cpp widgets/DisassemblerGraphView.cpp @@ -154,6 +155,7 @@ set(HEADER_FILES core/CutterCommon.h core/CutterDescriptions.h core/CutterJson.h + core/RizinCpp.h dialogs/EditStringDialog.h dialogs/WriteCommandsDialogs.h widgets/DisassemblerGraphView.h diff --git a/src/common/DecompilerHighlighter.cpp b/src/common/DecompilerHighlighter.cpp index 48183cc2..af7cb48f 100644 --- a/src/common/DecompilerHighlighter.cpp +++ b/src/common/DecompilerHighlighter.cpp @@ -49,8 +49,7 @@ void DecompilerHighlighter::highlightBlock(const QString &) size_t start = block.position(); size_t end = block.position() + block.length(); - std::unique_ptr annotations( - rz_annotated_code_annotations_range(code, start, end), &rz_pvector_free); + auto annotations = fromOwned(rz_annotated_code_annotations_range(code, start, end)); void **iter; rz_pvector_foreach(annotations.get(), iter) { diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index c69c4df5..ac8634b1 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -120,13 +120,6 @@ static void updateOwnedCharPtr(char *&variable, const QString &newValue) variable = strdup(data.data()); } -static QString fromOwnedCharPtr(char *str) -{ - QString result(str ? str : ""); - rz_mem_free(str); - return result; -} - static bool reg_sync(RzCore *core, RzRegisterType type, bool write) { if (rz_core_is_debug(core)) { @@ -782,11 +775,10 @@ PRzAnalysisBytes CutterCore::getRzAnalysisBytesSingle(RVA addr) CORE_LOCK(); ut8 buf[128]; rz_io_read_at(core->io, addr, buf, sizeof(buf)); - std::unique_ptr vec { - returnAtSeek( - [&]() { return rz_core_analysis_bytes(core, buf, sizeof(buf), 1); }, addr), - rz_pvector_free - }; + + auto seek = seekTemp(addr); + auto vec = fromOwned(rz_core_analysis_bytes(core, buf, sizeof(buf), 1)); + auto ab = vec && rz_pvector_len(vec.get()) > 0 ? reinterpret_cast(rz_pvector_pop_front(vec.get())) : nullptr; @@ -819,14 +811,20 @@ void CutterCore::editInstruction(RVA addr, const QString &inst, bool fillWithNop void CutterCore::nopInstruction(RVA addr) { CORE_LOCK(); - applyAtSeek([&]() { rz_core_hack(core, "nop"); }, addr); + { + auto seek = seekTemp(addr); + rz_core_hack(core, "nop"); + } emit instructionChanged(addr); } void CutterCore::jmpReverse(RVA addr) { CORE_LOCK(); - applyAtSeek([&]() { rz_core_hack(core, "recj"); }, addr); + { + auto seek = seekTemp(addr); + rz_core_hack(core, "recj"); + } emit instructionChanged(addr); } @@ -908,8 +906,8 @@ QString CutterCore::getString(RVA addr, uint64_t len, RzStrEnc encoding, bool es opt.length = len; opt.encoding = encoding; opt.escape_nl = escape_nl; - char *s = returnAtSeek([&]() { return rz_str_stringify_raw_buffer(&opt, NULL); }, addr); - return fromOwnedCharPtr(s); + auto seek = seekTemp(addr); + return fromOwnedCharPtr(rz_str_stringify_raw_buffer(&opt, NULL)); } QString CutterCore::getMetaString(RVA addr) @@ -993,12 +991,11 @@ void CutterCore::applyStructureOffset(const QString &structureOffset, RVA offset offset = getOffset(); } - applyAtSeek( - [&]() { - CORE_LOCK(); - rz_core_analysis_hint_set_offset(core, structureOffset.toUtf8().constData()); - }, - offset); + { + CORE_LOCK(); + auto seek = seekTemp(offset); + rz_core_analysis_hint_set_offset(core, structureOffset.toUtf8().constData()); + } emit instructionChanged(offset); } @@ -1084,22 +1081,19 @@ RVA CutterCore::prevOpAddr(RVA startAddr, int count) RVA CutterCore::nextOpAddr(RVA startAddr, int count) { CORE_LOCK(); - auto vec = returnAtSeek( - [&]() { - return rz_core_analysis_bytes(core, core->block, (int)core->blocksize, count + 1); - }, - startAddr); + auto seek = seekTemp(startAddr); + auto vec = + fromOwned(rz_core_analysis_bytes(core, core->block, (int)core->blocksize, count + 1)); + RVA addr = startAddr + 1; if (!vec) { return addr; } - auto ab = reinterpret_cast(rz_pvector_tail(vec)); + auto ab = reinterpret_cast(rz_pvector_tail(vec.get())); if (!(ab && ab->op)) { - rz_pvector_free(vec); return addr; } addr = ab->op->addr; - rz_pvector_free(vec); return addr; } @@ -4193,34 +4187,32 @@ void CutterCore::loadPDB(const QString &file) QList CutterCore::disassembleLines(RVA offset, int lines) { CORE_LOCK(); - RzPVector *vec = rz_pvector_new(reinterpret_cast(rz_analysis_disasm_text_free)); + auto vec = fromOwned( + rz_pvector_new(reinterpret_cast(rz_analysis_disasm_text_free))); if (!vec) { return {}; } RzCoreDisasmOptions options = {}; options.cbytes = 1; - options.vec = vec; - applyAtSeek( - [&]() { - if (rz_cons_singleton()->is_html) { - rz_cons_singleton()->is_html = false; - rz_cons_singleton()->was_html = true; - } - rz_core_print_disasm(core, offset, core->block, core->blocksize, lines, NULL, - &options); - }, - offset); + options.vec = vec.get(); + { + auto restoreSeek = seekTemp(offset); + if (rz_cons_singleton()->is_html) { + rz_cons_singleton()->is_html = false; + rz_cons_singleton()->was_html = true; + } + rz_core_print_disasm(core, offset, core->block, core->blocksize, lines, NULL, &options); + } QList r; - for (const auto &t : CutterPVector(vec)) { + for (const auto &t : CutterPVector(vec.get())) { DisassemblyLine line; line.offset = t->offset; line.text = ansiEscapeToHtml(t->text); line.arrow = t->arrow; r << line; } - rz_pvector_free(vec); return r; } diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 01bcc24d..c9b92636 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -156,33 +156,34 @@ public: return cmdRawAt(str.toUtf8().constData(), address); } - void applyAtSeek(const std::function &fn, RVA address) + class SeekReturn { - RVA oldOffset = getOffset(); - seekSilent(address); - fn(); - seekSilent(oldOffset); - } + RVA returnAddress; + bool empty = true; - template - T returnAtSeek(const std::function &fn, RVA address) - { - RVA oldOffset = getOffset(); - seekSilent(address); - T ret = fn(); - seekSilent(oldOffset); - return ret; - } - - std::unique_ptr> seekTemp(RVA address) - { - auto seekBack = [&](const RVA *x) { - seekSilent(*x); - delete x; + public: + SeekReturn(RVA returnAddress) : returnAddress(returnAddress), empty(false) {} + ~SeekReturn() + { + if (!empty) { + Core()->seekSilent(returnAddress); + } + } + SeekReturn(SeekReturn &&from) + { + if (this != &from) { + returnAddress = from.returnAddress; + empty = from.empty; + from.empty = true; + } }; - std::unique_ptr p { new RVA(getOffset()), seekBack }; + }; + + SeekReturn seekTemp(RVA address) + { + SeekReturn returner(getOffset()); seekSilent(address); - return p; + return returner; } CutterJson cmdj(const char *str); diff --git a/src/core/CutterCommon.h b/src/core/CutterCommon.h index 4adbf234..a118cd00 100644 --- a/src/core/CutterCommon.h +++ b/src/core/CutterCommon.h @@ -7,6 +7,7 @@ #include "rz_core.h" #include +#include "RizinCpp.h" // Workaround for compile errors on Windows #ifdef Q_OS_WIN @@ -14,103 +15,6 @@ # undef max #endif // Q_OS_WIN -// Rizin list iteration macros -#define CutterRzListForeach(list, it, type, x) \ - if (list) \ - for (it = list->head; it && ((x = static_cast(it->data))); it = it->n) - -#define CutterRzVectorForeach(vec, it, type) \ - if ((vec) && (vec)->a) \ - for (it = (type *)(vec)->a; \ - (char *)it != (char *)(vec)->a + ((vec)->len * (vec)->elem_size); \ - it = (type *)((char *)it + (vec)->elem_size)) - -template -class CutterPVector -{ -private: - const RzPVector *const vec; - -public: - class iterator : public std::iterator - { - private: - T **p; - - public: - iterator(T **p) : p(p) {} - iterator(const iterator &o) : p(o.p) {} - iterator &operator++() - { - p++; - return *this; - } - iterator operator++(int) - { - iterator tmp(*this); - operator++(); - return tmp; - } - bool operator==(const iterator &rhs) const { return p == rhs.p; } - bool operator!=(const iterator &rhs) const { return p != rhs.p; } - T *operator*() { return *p; } - }; - - CutterPVector(const RzPVector *vec) : vec(vec) {} - iterator begin() const { return iterator(reinterpret_cast(vec->v.a)); } - iterator end() const { return iterator(reinterpret_cast(vec->v.a) + vec->v.len); } -}; - -template -class CutterRzList -{ -private: - const RzList *const list; - -public: - class iterator : public std::iterator - { - private: - RzListIter *iter; - - public: - explicit iterator(RzListIter *iter) : iter(iter) {} - iterator(const iterator &o) : iter(o.iter) {} - iterator &operator++() - { - if (!iter) { - return *this; - } - iter = iter->n; - return *this; - } - iterator operator++(int) - { - iterator tmp(*this); - operator++(); - return tmp; - } - bool operator==(const iterator &rhs) const { return iter == rhs.iter; } - bool operator!=(const iterator &rhs) const { return iter != rhs.iter; } - T *operator*() - { - if (!iter) { - return nullptr; - } - return reinterpret_cast(iter->data); - } - }; - - explicit CutterRzList(const RzList *l) : list(l) {} - iterator begin() const - { - if (!list) { - return iterator(nullptr); - } - return iterator(list->head); - } - iterator end() const { return iterator(nullptr); } -}; // Global information for Cutter #define APPNAME "Cutter" diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index bfd3434d..6a840fcc 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -1768,12 +1768,12 @@ void MainWindow::on_actionExport_as_code_triggered() return; } - std::unique_ptr string { + + + auto string = fromOwned( dialog.selectedNameFilter() != instructionsInComments ? rz_lang_byte_array(buffer.data(), size, typMap[dialog.selectedNameFilter()]) - : rz_core_print_bytes_with_inst(rc, buffer.data(), 0, size), - free - }; + : rz_core_print_bytes_with_inst(rc, buffer.data(), 0, size)); fileOut << string.get(); } diff --git a/src/core/RizinCpp.cpp b/src/core/RizinCpp.cpp new file mode 100644 index 00000000..7418a3f9 --- /dev/null +++ b/src/core/RizinCpp.cpp @@ -0,0 +1,2 @@ +#include "RizinCpp.h" + diff --git a/src/core/RizinCpp.h b/src/core/RizinCpp.h new file mode 100644 index 00000000..ae4fcb03 --- /dev/null +++ b/src/core/RizinCpp.h @@ -0,0 +1,154 @@ +/** \file RizinCpp.h + * Various utilities for easier and safer interactions with Rizin + * from C++ code. + */ +#ifndef RIZINCPP_H +#define RIZINCPP_H + +#include "rz_core.h" +#include +#include + +static inline QString fromOwnedCharPtr(char *str) +{ + QString result(str ? str : ""); + rz_mem_free(str); + return result; +} + +template +std::unique_ptr fromOwned(T *data, F *freeFunction) +{ + return std::unique_ptr { data, freeFunction }; +} + +static inline std::unique_ptr fromOwned(char *text) +{ + return { text, rz_mem_free }; +} + +template +class FreeBinder +{ +public: + void operator()(T *data) { func(data); } +}; + +template +using UniquePtrC = std::unique_ptr>; + +template +using UniquePtrCP = UniquePtrC::type, func>; + +static inline auto fromOwned(RZ_OWN RzPVector *data) + -> UniquePtrCP +{ + return { data, {} }; +} + +static inline auto fromOwned(RZ_OWN RzList *data) + -> UniquePtrCP +{ + return { data, {} }; +} + +// Rizin list iteration macros +// deprecated, prefer using CutterPVector and CutterRzList instead +#define CutterRzListForeach(list, it, type, x) \ + if (list) \ + for (it = list->head; it && ((x = static_cast(it->data))); it = it->n) + +#define CutterRzVectorForeach(vec, it, type) \ + if ((vec) && (vec)->a) \ + for (it = (type *)(vec)->a; \ + (char *)it != (char *)(vec)->a + ((vec)->len * (vec)->elem_size); \ + it = (type *)((char *)it + (vec)->elem_size)) + +template +class CutterPVector +{ +private: + const RzPVector *const vec; + +public: + class iterator : public std::iterator + { + private: + T **p; + + public: + iterator(T **p) : p(p) {} + iterator(const iterator &o) : p(o.p) {} + iterator &operator++() + { + p++; + return *this; + } + iterator operator++(int) + { + iterator tmp(*this); + operator++(); + return tmp; + } + bool operator==(const iterator &rhs) const { return p == rhs.p; } + bool operator!=(const iterator &rhs) const { return p != rhs.p; } + T *operator*() { return *p; } + }; + + CutterPVector(const RzPVector *vec) : vec(vec) {} + iterator begin() const { return iterator(reinterpret_cast(vec->v.a)); } + iterator end() const { return iterator(reinterpret_cast(vec->v.a) + vec->v.len); } +}; + +template +class CutterRzList +{ +private: + const RzList *const list; + +public: + class iterator : public std::iterator + { + private: + RzListIter *iter; + + public: + explicit iterator(RzListIter *iter) : iter(iter) {} + iterator(const iterator &o) : iter(o.iter) {} + iterator &operator++() + { + if (!iter) { + return *this; + } + iter = iter->n; + return *this; + } + iterator operator++(int) + { + iterator tmp(*this); + operator++(); + return tmp; + } + bool operator==(const iterator &rhs) const { return iter == rhs.iter; } + bool operator!=(const iterator &rhs) const { return iter != rhs.iter; } + T *operator*() + { + if (!iter) { + return nullptr; + } + return reinterpret_cast(iter->data); + } + }; + + explicit CutterRzList(const RzList *l) : list(l) {} + iterator begin() const + { + if (!list) { + return iterator(nullptr); + } + return iterator(list->head); + } + iterator end() const { return iterator(nullptr); } +}; + +#endif // RIZINCPP_H diff --git a/src/dialogs/EditMethodDialog.cpp b/src/dialogs/EditMethodDialog.cpp index c9e9fdfc..9637b69b 100644 --- a/src/dialogs/EditMethodDialog.cpp +++ b/src/dialogs/EditMethodDialog.cpp @@ -86,11 +86,7 @@ bool EditMethodDialog::inputValid() QString EditMethodDialog::convertRealNameToName(const QString &realName) { - std::unique_ptr sanitizedCString( - rz_str_sanitize_sdb_key(realName.toUtf8().constData()), - [](const char *s) { rz_mem_free((void*)s); }); - - return QString(sanitizedCString.get()); + return fromOwnedCharPtr(rz_str_sanitize_sdb_key(realName.toUtf8().constData())); } void EditMethodDialog::setClass(const QString &className) diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index ddbfea65..50277c7d 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -314,9 +314,8 @@ void DisassemblyContextMenu::addDebugMenu() QVector DisassemblyContextMenu::getThingUsedHere(RVA offset) { RzCoreLocked core(Core()); - auto p = std::unique_ptr { - rz_core_analysis_name(core, offset), rz_core_analysis_name_free - }; + auto p = fromOwned( + rz_core_analysis_name(core, offset), rz_core_analysis_name_free); if (!p) { return {}; } diff --git a/src/widgets/CallGraph.cpp b/src/widgets/CallGraph.cpp index 2fbf603d..8c3d7e4a 100644 --- a/src/widgets/CallGraph.cpp +++ b/src/widgets/CallGraph.cpp @@ -74,7 +74,6 @@ static inline bool isBetween(ut64 a, ut64 x, ut64 b) return (a == UT64_MAX || a <= x) && (b == UT64_MAX || x <= b); } -using PRzList = std::unique_ptr; void CallGraphView::loadCurrentGraph() { @@ -90,7 +89,7 @@ void CallGraphView::loadCurrentGraph() GraphLayout::GraphBlock block; block.entry = fcn->addr; - auto xrefs = PRzList { rz_analysis_function_get_xrefs_from(fcn), rz_list_free }; + auto xrefs = fromOwned(rz_analysis_function_get_xrefs_from(fcn)); auto calls = std::unordered_set(); for (const auto &xref : CutterRzList(xrefs.get())) { const auto x = xref->to; diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index 63bf6832..fbd5ae39 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -193,9 +193,7 @@ void DisassemblerGraphView::loadCurrentGraph() windowTitle = tr("Graph"); if (fcn && RZ_STR_ISNOTEMPTY(fcn->name)) { - std::unique_ptr fcnName { - rz_str_escape_utf8_for_json(fcn->name, -1), std::free - }; + auto fcnName = fromOwned(rz_str_escape_utf8_for_json(fcn->name, -1)); windowTitle += QString("(%0)").arg(fcnName.get()); } else { windowTitle += "(Empty)"; @@ -267,10 +265,8 @@ void DisassemblerGraphView::loadCurrentGraph() } rz_io_read_at(core->io, bbi->addr, buf.get(), (int)bbi->size); - std::unique_ptr vec { - rz_pvector_new(reinterpret_cast(rz_analysis_disasm_text_free)), - rz_pvector_free - }; + auto vec = fromOwned( + rz_pvector_new(reinterpret_cast(rz_analysis_disasm_text_free))); if (!vec) { break; } diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index 864780c4..61dad3fe 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -234,12 +234,10 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const QStringList summary {}; { auto seeker = Core()->seekTemp(function.offset); - auto strings = std::unique_ptr { + auto strings = fromOwnedCharPtr( rz_core_print_disasm_strings(Core()->core(), RZ_CORE_DISASM_STRINGS_MODE_FUNCTION, - 0, NULL), - free - }; - summary = QString(strings.get()).split('\n', CUTTER_QT_SKIP_EMPTY_PARTS); + 0, NULL)); + summary = strings.split('\n', CUTTER_QT_SKIP_EMPTY_PARTS); } const QFont &fnt = Config()->getFont(); diff --git a/src/widgets/VisualNavbar.cpp b/src/widgets/VisualNavbar.cpp index 733430ca..3807fe0b 100644 --- a/src/widgets/VisualNavbar.cpp +++ b/src/widgets/VisualNavbar.cpp @@ -21,8 +21,7 @@ VisualNavbar::VisualNavbar(MainWindow *main, QWidget *parent) graphicsView(new QGraphicsView), seekGraphicsItem(nullptr), PCGraphicsItem(nullptr), - main(main), - stats(nullptr, rz_core_analysis_stats_free) + main(main) { Q_UNUSED(parent); @@ -119,7 +118,7 @@ void VisualNavbar::fetchStats() RzCoreLocked core(Core()); stats.reset(nullptr); - RzList *list = rz_core_get_boundaries_prot(core, -1, NULL, "search"); + auto list = fromOwned(rz_core_get_boundaries_prot(core, -1, NULL, "search")); if (!list) { return; } @@ -127,7 +126,7 @@ void VisualNavbar::fetchStats() RzIOMap *map; ut64 from = UT64_MAX; ut64 to = 0; - CutterRzListForeach (list, iter, RzIOMap, map) { + CutterRzListForeach (list.get(), iter, RzIOMap, map) { ut64 f = rz_itv_begin(map->itv); ut64 t = rz_itv_end(map->itv); if (f < from) { @@ -137,7 +136,6 @@ void VisualNavbar::fetchStats() to = t; } } - rz_list_free(list); to--; // rz_core_analysis_get_stats takes inclusive ranges if (to < from) { return; diff --git a/src/widgets/VisualNavbar.h b/src/widgets/VisualNavbar.h index 848f7b18..6fdc6ceb 100644 --- a/src/widgets/VisualNavbar.h +++ b/src/widgets/VisualNavbar.h @@ -47,7 +47,7 @@ private: QGraphicsRectItem *PCGraphicsItem; MainWindow *main; - std::unique_ptr stats; + UniquePtrC stats; unsigned int statsWidth = 0; unsigned int previousWidth = 0;