From e29585c672cd25fd711d0f60b2dda706e79d021b Mon Sep 17 00:00:00 2001 From: Itay Cohen Date: Thu, 15 Jul 2021 13:14:07 +0300 Subject: [PATCH 001/240] Fix wrong path in macos building instructions (#2718) --- docs/source/building.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/building.rst b/docs/source/building.rst index d7a03c12..9601b1b1 100644 --- a/docs/source/building.rst +++ b/docs/source/building.rst @@ -215,7 +215,7 @@ Recommended Way for dev builds mkdir build cd build - cmake .. -DCMAKE_PREFIX_PATH=/local/opt/qt5 + cmake .. -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5 make -------------- From 60343fa8b56db3718132b6cb45c015b174020ee8 Mon Sep 17 00:00:00 2001 From: Pulak Malhotra <56169176+PulakIIIT@users.noreply.github.com> Date: Fri, 16 Jul 2021 19:18:10 +0530 Subject: [PATCH 002/240] Heap widget wrapup (#2716) --- rizin | 2 +- src/CMakeLists.txt | 3 + src/core/Cutter.cpp | 34 ++++++++- src/core/Cutter.h | 13 ++++ src/core/CutterDescriptions.h | 6 ++ src/dialogs/ArenaInfoDialog.cpp | 25 +++++++ src/dialogs/ArenaInfoDialog.h | 25 +++++++ src/dialogs/ArenaInfoDialog.ui | 109 ++++++++++++++++++++++++++++ src/dialogs/GlibcHeapBinsDialog.ui | 14 ++-- src/dialogs/GlibcHeapInfoDialog.cpp | 63 ++++++++++++++-- src/dialogs/GlibcHeapInfoDialog.h | 3 + src/dialogs/GlibcHeapInfoDialog.ui | 19 +++-- src/widgets/GlibcHeapWidget.cpp | 17 +++++ src/widgets/GlibcHeapWidget.h | 1 + src/widgets/GlibcHeapWidget.ui | 51 ++++++++----- src/widgets/HeapBinsGraphView.cpp | 27 +++++-- src/widgets/HeapBinsGraphView.h | 1 + 17 files changed, 370 insertions(+), 43 deletions(-) create mode 100644 src/dialogs/ArenaInfoDialog.cpp create mode 100644 src/dialogs/ArenaInfoDialog.h create mode 100644 src/dialogs/ArenaInfoDialog.ui diff --git a/rizin b/rizin index 381f22d7..254c5119 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 381f22d7cc81bf2eb6663a690a715ff4f8f09373 +Subproject commit 254c5119e3563d05d02665cabbcba003c921cee8 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 147caa56..1d798902 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -146,6 +146,7 @@ set(SOURCES widgets/GlibcHeapWidget.cpp dialogs/GlibcHeapBinsDialog.cpp widgets/HeapBinsGraphView.cpp + dialogs/ArenaInfoDialog.cpp ) set(HEADER_FILES core/Cutter.h @@ -304,6 +305,7 @@ set(HEADER_FILES widgets/GlibcHeapWidget.h dialogs/GlibcHeapBinsDialog.h widgets/HeapBinsGraphView.h + dialogs/ArenaInfoDialog.h ) set(UI_FILES dialogs/AboutDialog.ui @@ -374,6 +376,7 @@ set(UI_FILES widgets/HeapDockWidget.ui widgets/GlibcHeapWidget.ui dialogs/GlibcHeapBinsDialog.ui + dialogs/ArenaInfoDialog.ui ) set(QRC_FILES resources.qrc diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index b5856535..12d50fce 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1592,6 +1592,12 @@ QVector CutterCore::getHeapChunks(RVA arena_addr) return chunks_vector; } +int CutterCore::getArchBits() +{ + CORE_LOCK(); + return core->dbg->bits; +} + QVector CutterCore::getArenas() { CORE_LOCK(); @@ -1606,6 +1612,12 @@ QVector CutterCore::getArenas() Arena arena; arena.offset = data->addr; arena.type = QString(data->type); + arena.last_remainder = data->arena->last_remainder; + arena.top = data->arena->top; + arena.next = data->arena->next; + arena.next_free = data->arena->next_free; + arena.system_mem = data->arena->system_mem; + arena.max_system_mem = data->arena->max_system_mem; arena_vector.append(arena); } @@ -1653,10 +1665,30 @@ QVector CutterCore::getHeapBins(ut64 arena_addr) } bins_vector.append(bin); } - + // get tcache bins + RzList *tcache_bins = rz_heap_tcache_content(core, arena_addr); + RzListIter *iter; + RzHeapBin *bin; + CutterRListForeach(tcache_bins, iter, RzHeapBin, bin) + { + if (!bin) { + continue; + } + if (!rz_list_length(bin->chunks)) { + rz_heap_bin_free_64(bin); + continue; + } + bins_vector.append(bin); + } return bins_vector; } +bool CutterCore::writeHeapChunk(RzHeapChunkSimple *chunk_simple) +{ + CORE_LOCK(); + return rz_heap_write_chunk(core, chunk_simple); +} + QJsonDocument CutterCore::getChildProcesses(int pid) { // Return the currently debugged process and it's children diff --git a/src/core/Cutter.h b/src/core/Cutter.h index d728d18c..c9245b74 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -419,7 +419,20 @@ public: * @return RzHeapChunkSimple struct pointer for the heap chunk */ RzHeapChunkSimple *getHeapChunk(ut64 addr); + /** + * @brief Get heap bins of an arena with given base address + * (including large, small, fast, unsorted, tcache) + * @param arena_addr Base address of the arena + * @return QVector of non empty RzHeapBin pointers + */ QVector getHeapBins(ut64 arena_addr); + /** + * @brief Write the given chunk header to memory + * @param chunkSimple RzHeapChunkSimple pointer of the chunk to be written + * @return true if the write succeeded else false + */ + bool writeHeapChunk(RzHeapChunkSimple *chunkSimple); + int getArchBits(); void startDebug(); void startEmulation(); /** diff --git a/src/core/CutterDescriptions.h b/src/core/CutterDescriptions.h index 2466d2d9..12170f92 100644 --- a/src/core/CutterDescriptions.h +++ b/src/core/CutterDescriptions.h @@ -375,6 +375,12 @@ struct Arena { RVA offset; QString type; + ut64 top; + ut64 last_remainder; + ut64 next; + ut64 next_free; + ut64 system_mem; + ut64 max_system_mem; }; Q_DECLARE_METATYPE(FunctionDescription) diff --git a/src/dialogs/ArenaInfoDialog.cpp b/src/dialogs/ArenaInfoDialog.cpp new file mode 100644 index 00000000..53634a75 --- /dev/null +++ b/src/dialogs/ArenaInfoDialog.cpp @@ -0,0 +1,25 @@ +#include "ArenaInfoDialog.h" +#include "ui_ArenaInfoDialog.h" + +ArenaInfoDialog::ArenaInfoDialog(Arena &arena, QWidget *parent) + : arena(arena), QDialog(parent), ui(new Ui::ArenaInfoDialog) +{ + ui->setupUi(this); + setWindowTitle("Arena @ " + RAddressString(arena.offset)); + updateContents(); +} + +void ArenaInfoDialog::updateContents() +{ + ui->lineEditTop->setText(RAddressString(arena.top)); + ui->lineEditLastRem->setText(RAddressString(arena.last_remainder)); + ui->lineEditNext->setText(RAddressString(arena.next)); + ui->lineEditNextfree->setText(RAddressString(arena.next_free)); + ui->lineEditSysMem->setText(RAddressString(arena.system_mem)); + ui->lineEditMaxMem->setText(RAddressString(arena.max_system_mem)); +} + +ArenaInfoDialog::~ArenaInfoDialog() +{ + delete ui; +} diff --git a/src/dialogs/ArenaInfoDialog.h b/src/dialogs/ArenaInfoDialog.h new file mode 100644 index 00000000..73f45345 --- /dev/null +++ b/src/dialogs/ArenaInfoDialog.h @@ -0,0 +1,25 @@ +#ifndef ARENAINFODIALOG_H +#define ARENAINFODIALOG_H + +#include +#include + +namespace Ui { +class ArenaInfoDialog; +} + +class ArenaInfoDialog : public QDialog +{ + Q_OBJECT + +public: + explicit ArenaInfoDialog(Arena &arena, QWidget *parent = nullptr); + ~ArenaInfoDialog(); + void updateContents(); + +private: + Ui::ArenaInfoDialog *ui; + Arena arena; +}; + +#endif // ARENAINFODIALOG_H diff --git a/src/dialogs/ArenaInfoDialog.ui b/src/dialogs/ArenaInfoDialog.ui new file mode 100644 index 00000000..31e1cd70 --- /dev/null +++ b/src/dialogs/ArenaInfoDialog.ui @@ -0,0 +1,109 @@ + + + ArenaInfoDialog + + + + 0 + 0 + 400 + 202 + + + + Dialog + + + + + + + + Top + + + + + + + Next + + + + + + + Next free + + + + + + + System Memory + + + + + + + Max Memory + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + true + + + + + + + Last Remainder + + + + + + + true + + + + + + + + + + diff --git a/src/dialogs/GlibcHeapBinsDialog.ui b/src/dialogs/GlibcHeapBinsDialog.ui index 36c7a689..1e45ee9a 100644 --- a/src/dialogs/GlibcHeapBinsDialog.ui +++ b/src/dialogs/GlibcHeapBinsDialog.ui @@ -4,10 +4,10 @@ - 0 - 0 - 883 - 544 + 0 + 0 + 883 + 544 @@ -27,7 +27,11 @@ - + + + true + + diff --git a/src/dialogs/GlibcHeapInfoDialog.cpp b/src/dialogs/GlibcHeapInfoDialog.cpp index 9e9f8c80..c22d6122 100644 --- a/src/dialogs/GlibcHeapInfoDialog.cpp +++ b/src/dialogs/GlibcHeapInfoDialog.cpp @@ -8,11 +8,6 @@ GlibcHeapInfoDialog::GlibcHeapInfoDialog(RVA offset, QString status, QWidget *pa { ui->setupUi(this); - // disable all the radio buttons for flag field so they are not user editable - this->ui->rbIM->setEnabled(false); - this->ui->rbNMA->setEnabled(false); - this->ui->rbPI->setEnabled(false); - // set window title QString windowTitle = tr("Chunk @ ") + RAddressString(offset); if (!this->status.isEmpty()) { @@ -20,6 +15,8 @@ GlibcHeapInfoDialog::GlibcHeapInfoDialog(RVA offset, QString status, QWidget *pa } this->setWindowTitle(windowTitle); + connect(ui->saveButton, &QPushButton::clicked, this, &GlibcHeapInfoDialog::saveChunkInfo); + updateFields(); } @@ -46,13 +43,69 @@ void GlibcHeapInfoDialog::updateFields() this->ui->prevSizeEdit->setText(RHexString(chunk->prev_size)); if (chunk->is_mmapped) { this->ui->rbIM->setChecked(true); + } else { + this->ui->rbIM->setChecked(false); } if (chunk->prev_inuse) { this->ui->rbPI->setChecked(true); + } else { + this->ui->rbPI->setChecked(false); } if (chunk->non_main_arena) { this->ui->rbNMA->setChecked(true); + } else { + this->ui->rbNMA->setChecked(false); } free(chunk); } + +void GlibcHeapInfoDialog::saveChunkInfo() +{ + QMessageBox msgBox; + msgBox.setText("Do you want to overwrite chunk metadata?"); + msgBox.setInformativeText( + "Any field which cannot be converted to a valid integer will be saved as zero"); + msgBox.setStandardButtons(QMessageBox::Save | QMessageBox::Cancel); + msgBox.setDefaultButton(QMessageBox::Save); + + int ret = msgBox.exec(); + switch (ret) { + case QMessageBox::Save: + // Save was clicked + RzHeapChunkSimple chunkSimple; + chunkSimple.size = Core()->math(ui->sizeEdit->text()); + chunkSimple.fd = Core()->math(ui->fdEdit->text()); + chunkSimple.bk = Core()->math(ui->bkEdit->text()); + chunkSimple.fd_nextsize = Core()->math(ui->fdnsEdit->text()); + chunkSimple.bk_nextsize = Core()->math(ui->bknsEdit->text()); + chunkSimple.addr = offset; + if (ui->rbIM->isChecked()) { + chunkSimple.is_mmapped = true; + } else { + chunkSimple.is_mmapped = false; + } + if (ui->rbNMA->isChecked()) { + chunkSimple.non_main_arena = true; + } else { + chunkSimple.non_main_arena = false; + } + if (ui->rbPI->isChecked()) { + chunkSimple.prev_inuse = true; + } else { + chunkSimple.prev_inuse = false; + } + if (Core()->writeHeapChunk(&chunkSimple)) { + updateFields(); + QMessageBox::information(this, tr("Chunk saved"), + tr("Chunk header successfully overwritten")); + } else { + QMessageBox::information(this, tr("Chunk not saved"), + tr("Chunk header not successfully overwritten")); + } + break; + case QMessageBox::Cancel: + // Cancel was clicked + break; + } +} \ No newline at end of file diff --git a/src/dialogs/GlibcHeapInfoDialog.h b/src/dialogs/GlibcHeapInfoDialog.h index 88cbb4c4..684628e0 100644 --- a/src/dialogs/GlibcHeapInfoDialog.h +++ b/src/dialogs/GlibcHeapInfoDialog.h @@ -16,6 +16,9 @@ public: explicit GlibcHeapInfoDialog(RVA offset, QString status, QWidget *parent = nullptr); ~GlibcHeapInfoDialog(); +private slots: + void saveChunkInfo(); + private: Ui::GlibcHeapInfoDialog *ui; void updateFields(); diff --git a/src/dialogs/GlibcHeapInfoDialog.ui b/src/dialogs/GlibcHeapInfoDialog.ui index 48f19c90..a41d4c73 100644 --- a/src/dialogs/GlibcHeapInfoDialog.ui +++ b/src/dialogs/GlibcHeapInfoDialog.ui @@ -46,7 +46,7 @@ Size of the heap chunk including metadata - true + false @@ -63,7 +63,7 @@ Link to next free chunk in bin's linked list - true + false @@ -80,7 +80,7 @@ Link to previous free chunk in bin's linked list - true + false @@ -90,7 +90,7 @@ Link to next larger free chunk (only for large chunks) - true + false @@ -114,7 +114,7 @@ Link to next smaller free chunk (for large chunks) - true + false @@ -124,7 +124,7 @@ Size of previous chunk (if free) - true + false @@ -189,6 +189,13 @@ + + + + Save + + + diff --git a/src/widgets/GlibcHeapWidget.cpp b/src/widgets/GlibcHeapWidget.cpp index 83378ad2..990ee210 100644 --- a/src/widgets/GlibcHeapWidget.cpp +++ b/src/widgets/GlibcHeapWidget.cpp @@ -1,4 +1,5 @@ #include +#include #include "GlibcHeapWidget.h" #include "ui_GlibcHeapWidget.h" #include "core/MainWindow.h" @@ -38,6 +39,7 @@ GlibcHeapWidget::GlibcHeapWidget(MainWindow *main, QWidget *parent) connect(chunkInfoAction, &QAction::triggered, this, &GlibcHeapWidget::viewChunkInfo); connect(binInfoAction, &QAction::triggered, this, &GlibcHeapWidget::viewBinInfo); connect(ui->binsButton, &QPushButton::clicked, this, &GlibcHeapWidget::viewBinInfo); + connect(ui->arenaButton, &QPushButton::clicked, this, &GlibcHeapWidget::viewArenaInfo); addressableItemContextMenu.addAction(chunkInfoAction); addressableItemContextMenu.addAction(binInfoAction); @@ -214,3 +216,18 @@ void GlibcHeapWidget::viewBinInfo() GlibcHeapBinsDialog heapBinsDialog(modelHeap->arena_addr, main, this); heapBinsDialog.exec(); } + +void GlibcHeapWidget::viewArenaInfo() +{ + // find the active arena + Arena currentArena; + for (auto &arena : arenas) { + if (arena.offset == modelHeap->arena_addr) { + currentArena = arena; + break; + } + } + + ArenaInfoDialog arenaInfoDialog(currentArena, this); + arenaInfoDialog.exec(); +} \ No newline at end of file diff --git a/src/widgets/GlibcHeapWidget.h b/src/widgets/GlibcHeapWidget.h index da6f110f..23a4d7bd 100644 --- a/src/widgets/GlibcHeapWidget.h +++ b/src/widgets/GlibcHeapWidget.h @@ -44,6 +44,7 @@ private slots: void onCurrentChanged(const QModelIndex ¤t, const QModelIndex &previous); void viewChunkInfo(); void viewBinInfo(); + void viewArenaInfo(); private: void updateArenas(); diff --git a/src/widgets/GlibcHeapWidget.ui b/src/widgets/GlibcHeapWidget.ui index ae2bd9f8..ce757d07 100644 --- a/src/widgets/GlibcHeapWidget.ui +++ b/src/widgets/GlibcHeapWidget.ui @@ -19,25 +19,38 @@ - - - - - - - - 0 - 0 - - - - View bins info for an arena - - - Bins - - - + + + + + + + + 0 + 0 + + + + Arena + + + + + + + + 0 + 0 + + + + View bins info for an arena + + + Bins + + + diff --git a/src/widgets/HeapBinsGraphView.cpp b/src/widgets/HeapBinsGraphView.cpp index 6d987468..97ae534d 100644 --- a/src/widgets/HeapBinsGraphView.cpp +++ b/src/widgets/HeapBinsGraphView.cpp @@ -11,6 +11,8 @@ HeapBinsGraphView::HeapBinsGraphView(QWidget *parent, RzHeapBin *bin, MainWindow connect(chunkInfoAction, &QAction::triggered, this, &HeapBinsGraphView::viewChunkInfo); + bits = Core()->getArchBits(); + enableAddresses(true); } @@ -30,7 +32,8 @@ void HeapBinsGraphView::loadCurrentGraph() QVector chunks; // if the bin is a fastbin or not - bool fast = QString(heapBin->type) == QString("Fast"); + bool singleLinkedBin = QString(heapBin->type) == QString("Fast") + || QString(heapBin->type) == QString("Tcache"); // store info about the chunks in a vector for easy access CutterRListForeach(heapBin->chunks, iter, RzHeapChunkListItem, item) @@ -45,7 +48,7 @@ void HeapBinsGraphView::loadCurrentGraph() + RHexString(chunkInfo->size) + "\nFd: " + RAddressString(chunkInfo->fd); // fastbins lack bk pointer - if (!fast) { + if (!singleLinkedBin) { content += "\nBk: " + RAddressString(chunkInfo->bk); } graphHeapChunk.fd = chunkInfo->fd; @@ -55,8 +58,8 @@ void HeapBinsGraphView::loadCurrentGraph() free(chunkInfo); } - // fast bins have single linked list and other bins have double linked list - if (fast) { + // fast and tcache bins have single linked list and other bins have double linked list + if (singleLinkedBin) { display_single_linked_list(chunks); } else { display_double_linked_list(chunks); @@ -68,19 +71,31 @@ void HeapBinsGraphView::loadCurrentGraph() void HeapBinsGraphView::display_single_linked_list(QVector chunks) { + bool tcache = QString(heapBin->type) == QString("Tcache"); + int ptrSize = bits; // add the graph block for the bin GraphLayout::GraphBlock gbBin; gbBin.entry = 1; gbBin.edges.emplace_back(heapBin->fd); QString content = tr(heapBin->type) + tr("bin ") + QString::number(heapBin->bin_num); - content += "\nFd: " + RAddressString(heapBin->fd); + if (tcache) { + content += "\nEntry: " + RAddressString(heapBin->fd); + } else { + content += "\nFd: " + RAddressString(heapBin->fd); + } addBlock(gbBin, content); // add the graph blocks for the chunks for (int i = 0; i < chunks.size(); i++) { GraphLayout::GraphBlock gbChunk; gbChunk.entry = chunks[i].addr; - gbChunk.edges.emplace_back(chunks[i].fd); + + if (tcache && chunks[i].fd) { + // base_address = address - 2 * PTR_SIZE + gbChunk.edges.emplace_back(chunks[i].fd - 2 * ptrSize); + } else { + gbChunk.edges.emplace_back(chunks[i].fd); + } if (i == chunks.size() - 1 && heapBin->message) { chunks[i].content += "\n" + QString(heapBin->message); diff --git a/src/widgets/HeapBinsGraphView.h b/src/widgets/HeapBinsGraphView.h index 99b8c128..1f3e6f6e 100644 --- a/src/widgets/HeapBinsGraphView.h +++ b/src/widgets/HeapBinsGraphView.h @@ -33,6 +33,7 @@ private: void display_double_linked_list(QVector); QAction *chunkInfoAction; RVA selectedBlock; + int bits; }; #endif // CUTTER_HEAPBINSGRAPHVIEW_H From a38d77c9690ea8160b152cde36ad97545aecbc66 Mon Sep 17 00:00:00 2001 From: Kamay Date: Sun, 25 Jul 2021 08:33:51 +0200 Subject: [PATCH 003/240] Improved function widget (#2659) --- src/common/Configuration.cpp | 2 +- src/img/icons/function_dark.svg | 210 +++++++++++++ src/img/icons/function_entry_dark.svg | 326 ++++++++++++++++++++ src/img/icons/function_entry_light.svg | 326 ++++++++++++++++++++ src/img/icons/function_export_dark.svg | 305 +++++++++++++++++++ src/img/icons/function_export_light.svg | 305 +++++++++++++++++++ src/img/icons/function_import_dark.svg | 229 +++++++++++++++ src/img/icons/function_import_light.svg | 229 +++++++++++++++ src/img/icons/function_light.svg | 210 +++++++++++++ src/img/icons/function_main_dark.svg | 376 ++++++++++++++++++++++++ src/img/icons/function_main_light.svg | 376 ++++++++++++++++++++++++ src/img/icons/function_tlscb_dark.svg | 230 +++++++++++++++ src/img/icons/function_tlscb_light.svg | 230 +++++++++++++++ src/img/icons/import_light.svg | 53 ---- src/resources.qrc | 13 +- src/widgets/FunctionsWidget.cpp | 58 +++- src/widgets/FunctionsWidget.h | 7 + 17 files changed, 3420 insertions(+), 65 deletions(-) create mode 100644 src/img/icons/function_dark.svg create mode 100644 src/img/icons/function_entry_dark.svg create mode 100644 src/img/icons/function_entry_light.svg create mode 100644 src/img/icons/function_export_dark.svg create mode 100644 src/img/icons/function_export_light.svg create mode 100644 src/img/icons/function_import_dark.svg create mode 100644 src/img/icons/function_import_light.svg create mode 100644 src/img/icons/function_light.svg create mode 100644 src/img/icons/function_main_dark.svg create mode 100644 src/img/icons/function_main_light.svg create mode 100644 src/img/icons/function_tlscb_dark.svg create mode 100644 src/img/icons/function_tlscb_light.svg delete mode 100644 src/img/icons/import_light.svg diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index a5be951a..756c59d1 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -39,7 +39,7 @@ const QHash> Configuration::cutterOptionColor { "gui.item_invalid", { { DarkFlag, QColor(0x9b, 0x9b, 0x9b) }, { LightFlag, QColor(0x9b, 0x9b, 0x9b) } } }, { "gui.main", - { { DarkFlag, QColor(0x00, 0x80, 0x00) }, { LightFlag, QColor(0x00, 0x80, 0x00) } } }, + { { DarkFlag, QColor(0x21, 0xd8, 0x93) }, { LightFlag, QColor(0x00, 0x80, 0x00) } } }, { "gui.item_unsafe", { { DarkFlag, QColor(0xff, 0x81, 0x7b) }, { LightFlag, QColor(0xff, 0x81, 0x7b) } } }, { "gui.navbar.seek", diff --git a/src/img/icons/function_dark.svg b/src/img/icons/function_dark.svg new file mode 100644 index 00000000..8999d724 --- /dev/null +++ b/src/img/icons/function_dark.svg @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/src/img/icons/function_entry_dark.svg b/src/img/icons/function_entry_dark.svg new file mode 100644 index 00000000..3a0812af --- /dev/null +++ b/src/img/icons/function_entry_dark.svg @@ -0,0 +1,326 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/src/img/icons/function_entry_light.svg b/src/img/icons/function_entry_light.svg new file mode 100644 index 00000000..7cedcef4 --- /dev/null +++ b/src/img/icons/function_entry_light.svg @@ -0,0 +1,326 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/src/img/icons/function_export_dark.svg b/src/img/icons/function_export_dark.svg new file mode 100644 index 00000000..4401642d --- /dev/null +++ b/src/img/icons/function_export_dark.svg @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/src/img/icons/function_export_light.svg b/src/img/icons/function_export_light.svg new file mode 100644 index 00000000..0fa11e16 --- /dev/null +++ b/src/img/icons/function_export_light.svg @@ -0,0 +1,305 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + diff --git a/src/img/icons/function_import_dark.svg b/src/img/icons/function_import_dark.svg new file mode 100644 index 00000000..333eac02 --- /dev/null +++ b/src/img/icons/function_import_dark.svg @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/src/img/icons/function_import_light.svg b/src/img/icons/function_import_light.svg new file mode 100644 index 00000000..c8944d0f --- /dev/null +++ b/src/img/icons/function_import_light.svg @@ -0,0 +1,229 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/src/img/icons/function_light.svg b/src/img/icons/function_light.svg new file mode 100644 index 00000000..bd3fe353 --- /dev/null +++ b/src/img/icons/function_light.svg @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + diff --git a/src/img/icons/function_main_dark.svg b/src/img/icons/function_main_dark.svg new file mode 100644 index 00000000..494988e1 --- /dev/null +++ b/src/img/icons/function_main_dark.svg @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/img/icons/function_main_light.svg b/src/img/icons/function_main_light.svg new file mode 100644 index 00000000..7b37066a --- /dev/null +++ b/src/img/icons/function_main_light.svg @@ -0,0 +1,376 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/img/icons/function_tlscb_dark.svg b/src/img/icons/function_tlscb_dark.svg new file mode 100644 index 00000000..8e0751d7 --- /dev/null +++ b/src/img/icons/function_tlscb_dark.svg @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/src/img/icons/function_tlscb_light.svg b/src/img/icons/function_tlscb_light.svg new file mode 100644 index 00000000..b29ec12d --- /dev/null +++ b/src/img/icons/function_tlscb_light.svg @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + diff --git a/src/img/icons/import_light.svg b/src/img/icons/import_light.svg deleted file mode 100644 index ec2e4e8f..00000000 --- a/src/img/icons/import_light.svg +++ /dev/null @@ -1,53 +0,0 @@ - - - -image/svg+xml \ No newline at end of file diff --git a/src/resources.qrc b/src/resources.qrc index f7cc7b12..0f80520b 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -89,7 +89,18 @@ img/icons/transfer.svg img/icons/transfer_white.svg img/icons/spin_light.svg - img/icons/import_light.svg + img/icons/function_light.svg + img/icons/function_import_light.svg + img/icons/function_entry_light.svg + img/icons/function_export_light.svg + img/icons/function_tlscb_light.svg + img/icons/function_main_light.svg + img/icons/function_dark.svg + img/icons/function_import_dark.svg + img/icons/function_entry_dark.svg + img/icons/function_export_dark.svg + img/icons/function_tlscb_dark.svg + img/icons/function_main_dark.svg img/icons/home.svg fonts/Anonymous Pro.ttf fonts/Inconsolata-Regular.ttf diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index b04f6169..b0e72d6c 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -17,6 +17,8 @@ #include #include #include +#include +#include namespace { @@ -36,7 +38,13 @@ FunctionModel::FunctionModel(QList *functions, QSet *i highlightFont(highlight_font), defaultFont(default_font), nested(nested), - currentIndex(-1) + currentIndex(-1), + iconFuncImpDark(":/img/icons/function_import_dark.svg"), + iconFuncImpLight(":/img/icons/function_import_light.svg"), + iconFuncMainDark(":/img/icons/function_main_dark.svg"), + iconFuncMainLight(":/img/icons/function_main_light.svg"), + iconFuncDark(":/img/icons/function_dark.svg"), + iconFuncLight(":/img/icons/function_light.svg") { connect(Core(), &CutterCore::seekChanged, this, &FunctionModel::seekChanged); @@ -101,6 +109,8 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const int function_index; bool subnode; + bool is_dark; + if (index.internalId() != 0) { // sub-node function_index = index.parent().row(); subnode = true; @@ -151,6 +161,8 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const return function.name; case SizeColumn: return QString::number(function.linearSize); + case ImportColumn: + return functionIsImport(function.offset) ? tr("true") : tr("false"); case OffsetColumn: return RAddressString(function.offset); case NargsColumn: @@ -172,13 +184,37 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const } } - case Qt::DecorationRole: - if (importAddresses->contains(function.offset) - && (nested ? false : index.column() == ImportColumn)) { - const static QIcon importIcon(":/img/icons/import_light.svg"); - return importIcon; + case Qt::DecorationRole: { + + // Check if we aren't inside a tree view + if (nested && subnode) { + return QVariant(); } + + if (index.column() == NameColumn) { + is_dark = Config()->windowColorIsDark(); + + if (functionIsImport(function.offset)) { + if (is_dark) { + return iconFuncImpDark; + } + return iconFuncImpLight; + + } else if (functionIsMain(function.offset)) { + if (is_dark) { + return iconFuncMainDark; + } + return iconFuncMainLight; + } + + if (is_dark) { + return iconFuncDark; + } + return iconFuncLight; + } + return QVariant(); + } case Qt::FontRole: if (currentIndex == function_index) @@ -214,8 +250,8 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const QString("
") .arg(fnt.family()) - .arg(qMax(6, fnt.pointSize() - 1)); // slightly decrease font size, to keep - // more text in the same box + .arg(qMax(6, fnt.pointSize() - 1)); // slightly decrease font size, to + // keep more text in the same box if (!disasmPreview.isEmpty()) toolTipContent += tr("
Disassembly " @@ -233,10 +269,12 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const } case Qt::ForegroundRole: - if (functionIsImport(function.offset)) + if (functionIsImport(function.offset)) { return QVariant(ConfigColor("gui.imports")); - if (functionIsMain(function.offset)) + } else if (functionIsMain(function.offset)) { return QVariant(ConfigColor("gui.main")); + } + return QVariant(this->property("color")); case FunctionDescriptionRole: diff --git a/src/widgets/FunctionsWidget.h b/src/widgets/FunctionsWidget.h index 99ab7656..40cd89b6 100644 --- a/src/widgets/FunctionsWidget.h +++ b/src/widgets/FunctionsWidget.h @@ -28,6 +28,13 @@ private: int currentIndex; + QIcon iconFuncImpDark; + QIcon iconFuncImpLight; + QIcon iconFuncMainDark; + QIcon iconFuncMainLight; + QIcon iconFuncDark; + QIcon iconFuncLight; + bool functionIsImport(ut64 addr) const; bool functionIsMain(ut64 addr) const; From f59797fb3d49a5513ac5d12354a7a91ebe373dcc Mon Sep 17 00:00:00 2001 From: GustavoLCR Date: Fri, 6 Aug 2021 05:56:50 -0300 Subject: [PATCH 004/240] Fix #2657 - Set cutter executable as WINDOWS subsystem (#2717) --- src/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1d798902..97aefbfb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -429,6 +429,7 @@ endif() if (WIN32) set(PLATFORM_RESOURCES "img/cutter.rc") + set(OPTIONS WIN32) else() set(PLATFORM_RESOURCES "") endif() @@ -440,7 +441,7 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" endif() -add_executable(Cutter ${UI_FILES} ${QRC_FILES} ${PLATFORM_RESOURCES} ${SOURCES} ${HEADER_FILES} ${BINDINGS_SOURCE}) +add_executable(Cutter ${OPTIONS} ${UI_FILES} ${QRC_FILES} ${PLATFORM_RESOURCES} ${SOURCES} ${HEADER_FILES} ${BINDINGS_SOURCE}) set_target_properties(Cutter PROPERTIES OUTPUT_NAME cutter RUNTIME_OUTPUT_DIRECTORY .. From 2d05ae259569cf6d4f13fdf1c5ae70449e48887a Mon Sep 17 00:00:00 2001 From: GustavoLCR Date: Thu, 12 Aug 2021 18:28:10 -0300 Subject: [PATCH 005/240] Fixes for debugging (#2727) * Fix continue until main not being enabled * Use Rizin API instead of commands * Fix attaching to a process with no file opened --- src/core/Cutter.cpp | 4 +++- src/widgets/DebugActions.cpp | 17 ++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 12d50fce..f6dbcda6 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1957,8 +1957,10 @@ void CutterCore::attachDebug(int pid) offsetPriorDebugging = getOffset(); } + QString attach_command = currentlyOpenFile.isEmpty() ? "o" : "oodf"; // attach to process with dbg plugin - asyncCmd("e cfg.debug = true; oodf dbg://" + QString::number(pid), debugTask); + asyncCmd("e cfg.debug=true;" + attach_command + " dbg://" + QString::number(pid), debugTask); + emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this, pid]() { diff --git a/src/widgets/DebugActions.cpp b/src/widgets/DebugActions.cpp index cf0b6e74..3ed1b877 100644 --- a/src/widgets/DebugActions.cpp +++ b/src/widgets/DebugActions.cpp @@ -249,10 +249,10 @@ DebugActions::DebugActions(QToolBar *toolBar, MainWindow *main) : QObject(main), void DebugActions::setButtonVisibleIfMainExists() { - // Use cmd because cmdRaw would not handle multiple commands concatenated - int mainExists = Core()->cmd("f?sym.main; ??").toInt(); + RzCoreLocked core(Core()->core()); // if main is not a flag we hide the continue until main button - if (!mainExists) { + if (!rz_flag_get(Core()->core()->flags, "sym.main") + && !rz_flag_get(Core()->core()->flags, "main")) { actionContinueUntilMain->setVisible(false); continueUntilButton->setDefaultAction(actionContinueUntilCall); } @@ -273,8 +273,15 @@ void DebugActions::showDebugWarning() void DebugActions::continueUntilMain() { - QString mainAddr = Core()->cmdRaw("?v sym.main"); - Core()->continueUntilDebug(mainAddr); + RzCoreLocked core(Core()->core()); + RzFlagItem *main_flag = rz_flag_get(Core()->core()->flags, "sym.main"); + if (!main_flag) { + main_flag = rz_flag_get(Core()->core()->flags, "main"); + if (!main_flag) { + return; + } + } + Core()->continueUntilDebug(QString::number(main_flag->offset)); } void DebugActions::attachRemoteDebugger() From 62ecf3fb2a79e613d11392088851e0e83900f9bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Thu, 9 Sep 2021 23:07:54 +0200 Subject: [PATCH 006/240] Set rz-ghidra to Fixed Compatible Commit (#2743) --- dist/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index 9f2dc288..d58624eb 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -110,7 +110,8 @@ if(CUTTER_PACKAGE_RZ_GHIDRA) ExternalProject_Add(rz-ghidra GIT_REPOSITORY https://github.com/rizinorg/rz-ghidra #GIT_TAG v0.2.0 - GIT_TAG dev + GIT_TAG 40ea3766d1bb283e255e31b9e7c3a61885dd3cb0 + #GIT_TAG dev #GIT_SHALLOW ON # disable this line when using commit hash CONFIGURE_COMMAND "" BUILD_COMMAND "" From f42069369cc718b20c205f9b7653a1e04aad689f Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Tue, 7 Sep 2021 11:12:07 +0200 Subject: [PATCH 007/240] Make use of new RzType API in Rizin --- rizin | 2 +- src/core/Cutter.cpp | 133 ++++++++-------------------- src/core/Cutter.h | 13 ++- src/dialogs/EditVariablesDialog.cpp | 30 +++---- src/widgets/TypesWidget.cpp | 9 +- src/widgets/TypesWidget.h | 4 +- 6 files changed, 67 insertions(+), 124 deletions(-) diff --git a/rizin b/rizin index 254c5119..c9f9aea2 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 254c5119e3563d05d02665cabbcba003c921cee8 +Subproject commit c9f9aea2924d2f086b5a6b1ed0216b531faea125 diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index f6dbcda6..79192f8a 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3519,145 +3519,88 @@ QList CutterCore::getAllTypes() return types; } -QList CutterCore::getAllPrimitiveTypes() +QList CutterCore::getBaseType(RzBaseTypeKind kind, const char *category) { CORE_LOCK(); - QList primitiveTypes; + QList types; - QJsonArray typesArray = cmdj("tj").array(); - for (const QJsonValue &value : typesArray) { - QJsonObject typeObject = value.toObject(); + RzList *ts = rz_type_db_get_base_types_of_kind(core->analysis->typedb, kind); + RzBaseType *type; + RzListIter *iter; + CutterRListForeach (ts, iter, RzBaseType, type) { TypeDescription exp; - exp.type = typeObject[RJsonKey::type].toString(); - exp.size = typeObject[RJsonKey::size].toVariant().toULongLong(); - exp.format = typeObject[RJsonKey::format].toString(); - exp.category = tr("Primitive"); - primitiveTypes << exp; + exp.type = type->name; + exp.size = rz_type_db_base_get_bitsize(core->analysis->typedb, type); + exp.format = rz_type_format(core->analysis->typedb, type->name); + exp.category = tr(category); + types << exp; } + rz_list_free(ts); - return primitiveTypes; + return types; +} + +QList CutterCore::getAllPrimitiveTypes() +{ + return getBaseType(RZ_BASE_TYPE_KIND_ATOMIC, "Primitive"); } QList CutterCore::getAllUnions() { - CORE_LOCK(); - QList unions; - - QJsonArray typesArray = cmdj("tuj").array(); - for (const QJsonValue value : typesArray) { - QJsonObject typeObject = value.toObject(); - - TypeDescription exp; - - exp.type = typeObject[RJsonKey::type].toString(); - exp.size = typeObject[RJsonKey::size].toVariant().toULongLong(); - exp.category = "Union"; - unions << exp; - } - - return unions; + return getBaseType(RZ_BASE_TYPE_KIND_UNION, "Union"); } QList CutterCore::getAllStructs() { - CORE_LOCK(); - QList structs; - - QJsonArray typesArray = cmdj("tsj").array(); - for (const QJsonValue value : typesArray) { - QJsonObject typeObject = value.toObject(); - - TypeDescription exp; - - exp.type = typeObject[RJsonKey::type].toString(); - exp.size = typeObject[RJsonKey::size].toVariant().toULongLong(); - exp.category = "Struct"; - structs << exp; - } - - return structs; + return getBaseType(RZ_BASE_TYPE_KIND_STRUCT, "Struct"); } QList CutterCore::getAllEnums() { - CORE_LOCK(); - QList enums; - - QJsonObject typesObject = cmdj("tej").object(); - for (QString key : typesObject.keys()) { - TypeDescription exp; - exp.type = key; - exp.size = 0; - exp.category = "Enum"; - enums << exp; - } - - return enums; + return getBaseType(RZ_BASE_TYPE_KIND_ENUM, "Enum"); } QList CutterCore::getAllTypedefs() { - CORE_LOCK(); - QList typeDefs; - - QJsonObject typesObject = cmdj("ttj").object(); - for (QString key : typesObject.keys()) { - TypeDescription exp; - exp.type = key; - exp.size = 0; - exp.category = "Typedef"; - typeDefs << exp; - } - - return typeDefs; + return getBaseType(RZ_BASE_TYPE_KIND_TYPEDEF, "Typedef"); } QString CutterCore::addTypes(const char *str) { CORE_LOCK(); char *error_msg = nullptr; - char *parsed = rz_type_parse_c_string(core->analysis->typedb, str, &error_msg); + int parsed = rz_type_parse_string(core->analysis->typedb, str, &error_msg); QString error; - if (!parsed) { - if (error_msg) { - error = error_msg; - rz_mem_free(error_msg); - } - return error; - } - - rz_type_db_save_parsed_type(core->analysis->typedb, parsed); - rz_mem_free(parsed); - - if (error_msg) { + if (!parsed && error_msg) { error = error_msg; rz_mem_free(error_msg); + } else if (!parsed) { + error = QString("Failed to load new type %1").arg(str); } return error; } -QString CutterCore::getTypeAsC(QString name, QString category) +QString CutterCore::getTypeAsC(QString name) { CORE_LOCK(); QString output = "Failed to fetch the output."; - if (name.isEmpty() || category.isEmpty()) { + if (name.isEmpty()) { return output; } - QString typeName = sanitizeStringForCommand(name); - if (category == "Struct") { - output = cmdRaw(QString("tsc %1").arg(typeName)); - } else if (category == "Union") { - output = cmdRaw(QString("tuc %1").arg(typeName)); - } else if (category == "Enum") { - output = cmdRaw(QString("tec %1").arg(typeName)); - } else if (category == "Typedef") { - output = cmdRaw(QString("ttc %1").arg(typeName)); - } - return output; + char *earg = rz_cmd_escape_arg(name.toUtf8().constData(), RZ_CMD_ESCAPE_ONE_ARG); + // TODO: use API for `tc` command once available + QString result = cmd(QString("tc %1").arg(earg)); + free(earg); + return result; +} + +bool CutterCore::deleteType(const char *typeName) { + CORE_LOCK(); + return rz_type_db_del(core->analysis->typedb, typeName); } bool CutterCore::isAddressMapped(RVA addr) diff --git a/src/core/Cutter.h b/src/core/Cutter.h index c9245b74..375943d1 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -590,11 +590,10 @@ public: /** * @brief Fetching the C representation of a given Type - * @param name - the name or the type of the given Type / Struct - * @param category - the category of the given Type (Struct, Union, Enum, ...) + * @param name - the name or the type of the given Type * @return The type decleration as C output */ - QString getTypeAsC(QString name, QString category); + QString getTypeAsC(QString name); /** * @brief Adds new types @@ -608,6 +607,13 @@ public: QString addTypes(const char *str); QString addTypes(const QString &str) { return addTypes(str.toUtf8().constData()); } + /** + * @brief Remove a type + * @param typeName Name of the type to remove + */ + bool deleteType(const char *typeName); + bool deleteType(QString typeName) { return deleteType(typeName.toUtf8().constData()); } + /** * @brief Checks if the given address is mapped to a region * @param addr The address to be checked @@ -788,6 +794,7 @@ private: RizinTaskDialog *debugTaskDialog; QVector getCutterRCFilePaths() const; + QList getBaseType(RzBaseTypeKind kind, const char *category); }; class CUTTER_EXPORT RzCoreLocked diff --git a/src/dialogs/EditVariablesDialog.cpp b/src/dialogs/EditVariablesDialog.cpp index fe50bc38..08966071 100644 --- a/src/dialogs/EditVariablesDialog.cpp +++ b/src/dialogs/EditVariablesDialog.cpp @@ -84,26 +84,18 @@ void EditVariablesDialog::updateFields() ui->typeComboBox->setCurrentText(desc.type); } +static void addTypeDescriptionsToComboBox(QComboBox *comboBox, QList list) { + for (const TypeDescription &thisType : list) { + comboBox->addItem(thisType.type); + } + comboBox->insertSeparator(comboBox->count()); +} + void EditVariablesDialog::populateTypesComboBox() { - // gets all loaded types, structures and enums and puts them in a list + addTypeDescriptionsToComboBox(ui->typeComboBox, Core()->getAllStructs()); + addTypeDescriptionsToComboBox(ui->typeComboBox, Core()->getAllPrimitiveTypes()); + addTypeDescriptionsToComboBox(ui->typeComboBox, Core()->getAllEnums()); + addTypeDescriptionsToComboBox(ui->typeComboBox, Core()->getAllTypedefs()); - QStringList userStructures; - QStringList userEnumerations; - QList primitiveTypesTypeList; - - userStructures = Core()->cmdList("ts"); - ui->typeComboBox->addItems(userStructures); - ui->typeComboBox->insertSeparator(ui->typeComboBox->count()); - - primitiveTypesTypeList = Core()->getAllPrimitiveTypes(); - - for (const TypeDescription &thisType : primitiveTypesTypeList) { - ui->typeComboBox->addItem(thisType.type); - } - - ui->typeComboBox->insertSeparator(ui->typeComboBox->count()); - - userEnumerations = Core()->cmdList("te"); - ui->typeComboBox->addItems(userEnumerations); } diff --git a/src/widgets/TypesWidget.cpp b/src/widgets/TypesWidget.cpp index 91cf9551..c9963c79 100644 --- a/src/widgets/TypesWidget.cpp +++ b/src/widgets/TypesWidget.cpp @@ -76,7 +76,7 @@ QVariant TypesModel::headerData(int section, Qt::Orientation, int role) const bool TypesModel::removeRows(int row, int count, const QModelIndex &parent) { - Core()->cmdRaw("t-" + types->at(row).type); + Core()->deleteType(types->at(row).type); beginRemoveRows(parent, row, row + count - 1); while (count--) { types->removeAt(row); @@ -275,7 +275,8 @@ void TypesWidget::on_actionExport_Types_triggered() return; } QTextStream fileOut(&file); - fileOut << Core()->cmdRaw("tc"); + // TODO: use API for `tc` command once available + fileOut << Core()->cmd("tc"); file.close(); } @@ -304,7 +305,7 @@ void TypesWidget::viewType(bool readOnly) } else { dialog.setWindowTitle(tr("View Type: ") + t.type + tr(" (Read Only)")); } - dialog.fillTextArea(Core()->getTypeAsC(t.type, t.category)); + dialog.fillTextArea(Core()->getTypeAsC(t.type)); dialog.exec(); } @@ -351,7 +352,7 @@ void TypesWidget::typeItemDoubleClicked(const QModelIndex &index) if (t.category == "Primitive") { return; } - dialog.fillTextArea(Core()->getTypeAsC(t.type, t.category)); + dialog.fillTextArea(Core()->getTypeAsC(t.type)); dialog.setWindowTitle(tr("View Type: ") + t.type + tr(" (Read Only)")); dialog.exec(); } diff --git a/src/widgets/TypesWidget.h b/src/widgets/TypesWidget.h index ddddeb09..e567a146 100644 --- a/src/widgets/TypesWidget.h +++ b/src/widgets/TypesWidget.h @@ -31,7 +31,7 @@ private: QList *types; public: - enum Columns { TYPE = 0, SIZE, FORMAT, CATEGORY, COUNT }; + enum Columns { TYPE = 0, SIZE, CATEGORY, FORMAT, COUNT }; static const int TypeDescriptionRole = Qt::UserRole; TypesModel(QList *types, QObject *parent = nullptr); @@ -81,7 +81,7 @@ private slots: /** * @brief Executed on clicking the Export Types option in the context menu * It shows the user a file dialog box to select a file where the types - * will be exported. It uses the "tc" command of Rizin to export the types. + * will be exported. */ void on_actionExport_Types_triggered(); From a3bc43259ccb7b1984c2bb3d4065ed048a1ff4e9 Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Thu, 9 Sep 2021 20:39:56 +0200 Subject: [PATCH 008/240] Fix code after change in rz_project_save_file API --- src/core/MainWindow.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index 78b8dc7c..6a899239 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -695,7 +695,7 @@ RzProjectErr MainWindow::saveProject(bool *canceled) if (canceled) { *canceled = false; } - RzProjectErr err = rz_project_save_file(RzCoreLocked(core), file.toUtf8().constData()); + RzProjectErr err = rz_project_save_file(RzCoreLocked(core), file.toUtf8().constData(), false); if (err == RZ_PROJECT_ERR_SUCCESS) { Config()->addRecentProject(file); } @@ -724,7 +724,7 @@ RzProjectErr MainWindow::saveProjectAs(bool *canceled) if (canceled) { *canceled = false; } - RzProjectErr err = rz_project_save_file(RzCoreLocked(core), file.toUtf8().constData()); + RzProjectErr err = rz_project_save_file(RzCoreLocked(core), file.toUtf8().constData(), false); if (err == RZ_PROJECT_ERR_SUCCESS) { Config()->addRecentProject(file); } From f4227d5b4b9e0dd9d8aca9a4814da3d78a26174a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 10 Sep 2021 14:35:13 +0200 Subject: [PATCH 009/240] Update rz-ghidra for Rizin --- dist/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index d58624eb..f72cf261 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -110,7 +110,7 @@ if(CUTTER_PACKAGE_RZ_GHIDRA) ExternalProject_Add(rz-ghidra GIT_REPOSITORY https://github.com/rizinorg/rz-ghidra #GIT_TAG v0.2.0 - GIT_TAG 40ea3766d1bb283e255e31b9e7c3a61885dd3cb0 + GIT_TAG f2f1e48031442789fc866f7290b63b18b6493771 #GIT_TAG dev #GIT_SHALLOW ON # disable this line when using commit hash CONFIGURE_COMMAND "" From 3c4fe781aba8ecb84eb63f74b1532844c3e12cca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 10 Sep 2021 17:51:59 +0200 Subject: [PATCH 010/240] Fix Versions in Info.plist (Fix #2679) (#2740) --- dist/macos/Info.plist.in | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/macos/Info.plist.in b/dist/macos/Info.plist.in index 0da08172..da869638 100644 --- a/dist/macos/Info.plist.in +++ b/dist/macos/Info.plist.in @@ -7,9 +7,9 @@ CFBundleExecutable cutter CFBundleVersion - @FULL_VERSION@ + @CUTTER_VERSION_FULL@ CFBundleShortVersionString - @FULL_VERSION@ + @CUTTER_VERSION_FULL@ NSHumanReadableCopyright Licensed under the GPLv3 by the Cutter developers. CFBundleIconFile From 394a1eb27d8737f429fe9cacf6a3dbe07f2651c4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 10 Sep 2021 17:53:42 +0200 Subject: [PATCH 011/240] Enforce Cutter-local sleighhome on macOS only if Packaging is Enabled (#2741) --- src/CutterApplication.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index 0b696400..60937679 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -170,7 +170,7 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc } #endif -#ifdef Q_OS_MACOS +#if defined(Q_OS_MACOS) && defined(CUTTER_ENABLE_PACKAGING) { auto rzprefix = QDir(QCoreApplication::applicationDirPath()); // Contents/MacOS rzprefix.cdUp(); // Contents From 77c22b37c877dec591f107f6e036c7d3adaaaa0e Mon Sep 17 00:00:00 2001 From: Surendrajat Date: Sat, 11 Sep 2021 16:46:52 +0530 Subject: [PATCH 012/240] CI: use Ubuntu 18.04 as oldest supported build system (#2736) --- .github/workflows/ccpp.yml | 43 ++++++++++++-------------------------- 1 file changed, 13 insertions(+), 30 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 9feece08..3ab3426b 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -17,7 +17,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-18.04, ubuntu-16.04, macos-latest, windows-2016] + os: [ubuntu-20.04, ubuntu-18.04, macos-latest, windows-2016] python-version: [3.7.x] system-deps: [false] cc-override: [default] @@ -25,12 +25,12 @@ jobs: include: - os: windows-2016 package: true - - os: ubuntu-16.04 # ensure that Cutter can be built at least in basic config on Ubuntu 16.04 using sytem libraries - python-version: 3.5.10 + - os: ubuntu-18.04 # ensure that Cutter can be built at least in basic config on Ubuntu 18.04 using sytem libraries + python-version: 3.6.x system-deps: true - cc-override: '/usr/bin/gcc-5' - cxx-override: '/usr/bin/g++-5' - - os: ubuntu-16.04 # release package build + cc-override: '/usr/bin/gcc-7' + cxx-override: '/usr/bin/g++-7' + - os: ubuntu-18.04 # release package build system-deps: false package: true # Prevent one job from pausing the rest @@ -43,28 +43,12 @@ jobs: - name: apt dependencies if: contains(matrix.os, 'ubuntu') run: | - sudo apt-get install libgraphviz-dev mesa-common-dev libxkbcommon-x11-dev libclang-8-dev llvm-8 - if [[ "${{ matrix.os }}" = "ubuntu-16.04" ]] + sudo apt-get update + sudo apt-get install libgraphviz-dev mesa-common-dev libxkbcommon-x11-dev libclang-8-dev llvm-8 ninja-build + if [[ "${{ matrix.os }}" = "ubuntu-18.04" ]] then - sudo apt-get install ninja-build/xenial-backports libxcb1-dev libxkbcommon-dev libxcb-*-dev - if [[ "${{ matrix.system-deps }}" = "true" ]] - then - sudo apt-get install cmake - sudo apt-get install --allow-downgrades \ - g++-5=5.4.\* \ - gcc-5=5.4.\* \ - gcc-5-base=5.4.\* \ - libstdc++-5-dev=5.4.\* \ - cpp-5=5.4.\* \ - libgcc-5-dev=5.4.\* \ - libasan2=5.4.\* \ - libmpx0=5.4.\* - fi - # make sure cmake that was just installed is at the front of path before - # additional software installed by GitHub - echo /usr/bin >> $GITHUB_PATH - else - sudo apt-get install ninja-build + # install additional packages needed for appimage + sudo apt-get install libxcb1-dev libxkbcommon-dev libxcb-*-dev libegl1 fi if [[ "${{ matrix.system-deps }}" = "true" ]] then @@ -84,8 +68,7 @@ jobs: brew install pkg-config - name: py dependencies run: | - # 0.56.1 doesn't work with python 3.5 on Ubuntu 16.04 - pip install meson==0.56.0 + pip install meson - name: Prepare package id shell: bash run: | @@ -157,7 +140,7 @@ jobs: # export LD_LIBRARY_PATH=${APP_PREFIX}/lib:$Shiboken2_ROOT/lib export PATH=$PATH:${APP_PREFIX}/bin "../scripts/jsdec.sh" --prefix=`pwd`/appdir/usr - wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/6/linuxdeployqt-6-x86_64.AppImage" + wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" chmod a+x linuxdeployqt*.AppImage rm -fv "../cutter-deps/qt/plugins/imageformats/libqjp2.so" # ./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop -executable=./appdir/usr/bin/python3 -bundle-non-qt-libs -no-strip -exclude-libs=libnss3.so,libnssutil3.so,libqjp2.so -ignore-glob=usr/lib/python3.9/**/* -verbose=2 From 40fa86c8ca8bc418675b9a62d43f1a6f4b224adb Mon Sep 17 00:00:00 2001 From: Maria Date: Sat, 11 Sep 2021 14:19:05 +0300 Subject: [PATCH 013/240] Fix Restoring "Show Disassembly as" in Preferences (Fix #2726, #2748) --- src/dialogs/preferences/AsmOptionsWidget.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/dialogs/preferences/AsmOptionsWidget.cpp b/src/dialogs/preferences/AsmOptionsWidget.cpp index fabd53a9..0a67daec 100644 --- a/src/dialogs/preferences/AsmOptionsWidget.cpp +++ b/src/dialogs/preferences/AsmOptionsWidget.cpp @@ -96,6 +96,16 @@ void AsmOptionsWidget::updateAsmOptionsFromVars() bool varsubEnabled = Config()->getConfigBool("asm.sub.var"); ui->varsubOnlyCheckBox->setEnabled(varsubEnabled); + ui->asmComboBox->blockSignals(true); + if (Config()->getConfigBool("asm.esil")) { + ui->asmComboBox->setCurrentIndex(1); + } else if (Config()->getConfigBool("asm.pseudo")) { + ui->asmComboBox->setCurrentIndex(2); + } else { + ui->asmComboBox->setCurrentIndex(0); + } + ui->asmComboBox->blockSignals(false); + QString currentSyntax = Config()->getConfigString("asm.syntax"); for (int i = 0; i < ui->syntaxComboBox->count(); i++) { if (ui->syntaxComboBox->itemData(i) == currentSyntax) { From 0dcdb0f1e9a5d7d2e821abf38b894eeaf0ba477c Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Tue, 14 Sep 2021 15:21:21 +0800 Subject: [PATCH 014/240] Update Rizin to the latest stable (#2753) --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index c9f9aea2..004edb89 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit c9f9aea2924d2f086b5a6b1ed0216b531faea125 +Subproject commit 004edb899fe0a841ce4226c6b57c198c0baff402 From e219be425319bd5a7c14260a06b76c6323d875d3 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Tue, 14 Sep 2021 16:13:19 +0800 Subject: [PATCH 015/240] Use seek history API instead of command (#2754) --- src/core/Cutter.cpp | 10 +++++----- src/core/MainWindow.cpp | 24 ++++++++++++++++++------ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 79192f8a..9c683625 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -585,7 +585,7 @@ QStringList CutterCore::autocomplete(const QString &cmd, RzLinePromptType prompt /** * @brief CutterCore::loadFile - * Load initial file. TODO Maybe use the "o" commands? + * Load initial file. * @param path File path * @param baddr Base (RzBin) address * @param mapaddr Map address @@ -2682,10 +2682,10 @@ QList CutterCore::getSeekHistory() { CORE_LOCK(); QList ret; - - QJsonArray jsonArray = cmdj("sj").array(); - for (const QJsonValue &value : jsonArray) - ret << value.toVariant().toULongLong(); + RzListIter *it; + RzCoreSeekItem *undo; + RzList *list = rz_core_seek_list(core); + CutterRListForeach(list, it, RzCoreSeekItem, undo) { ret << undo->offset; } return ret; } diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index 6a899239..0921293f 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -1127,14 +1127,26 @@ void MainWindow::updateHistoryMenu(QMenu *menu, bool redo) // not too short so that reasonable length c++ names can be seen most of the time const int MAX_NAME_LENGTH = 64; - auto hist = Core()->cmdj("sj"); + RzListIter *it; + RzCoreSeekItem *undo; + RzCoreLocked core(Core()); + RzList *list = rz_core_seek_list(core); + bool history = true; QList actions; - for (auto item : Core()->cmdj("sj").array()) { - QJsonObject obj = item.toObject(); - QString name = obj["name"].toString(); - RVA offset = obj["offset"].toVariant().toULongLong(); - bool current = obj["current"].toBool(false); + CutterRListForeach(list, it, RzCoreSeekItem, undo) { + RzFlagItem *f = rz_flag_get_at(core->flags, undo->offset, true); + char *fname = NULL; + if (f) { + if (f->offset != undo->offset) { + fname = rz_str_newf("%s+%" PFMT64d, f->name, undo->offset - f->offset); + } else { + fname = strdup(f->name); + } + } + QString name = fname; + RVA offset = undo->offset; + bool current = undo->is_current; if (current) { history = false; } From 417a0a222183afd4048bbeecad1b2f2cf3e37c83 Mon Sep 17 00:00:00 2001 From: Maria Date: Tue, 14 Sep 2021 16:24:47 +0300 Subject: [PATCH 016/240] Complete Color Theme Lists (Fix #2672) (#2752) --- src/common/Configuration.cpp | 15 +++++++++++---- src/widgets/ColorThemeComboBox.cpp | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 756c59d1..929b9173 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -21,10 +21,17 @@ * and for light - only light ones. */ const QHash Configuration::relevantThemes = { - { "ayu", DarkFlag }, { "consonance", DarkFlag }, { "darkda", DarkFlag }, - { "onedark", DarkFlag }, { "solarized", DarkFlag }, { "zenburn", DarkFlag }, - { "cutter", LightFlag }, { "dark", LightFlag }, { "matrix", LightFlag }, - { "tango", LightFlag }, { "white", LightFlag } + { "ayu", DarkFlag }, { "basic", DarkFlag }, { "behelit", DarkFlag }, + { "bold", DarkFlag }, { "bright", DarkFlag }, { "consonance", DarkFlag }, + { "darkda", DarkFlag }, { "defragger", DarkFlag }, { "focus", DarkFlag }, + { "gentoo", DarkFlag }, { "lima", DarkFlag }, { "monokai", DarkFlag }, + { "ogray", DarkFlag }, { "onedark", DarkFlag }, { "pink", DarkFlag }, + { "rasta", DarkFlag }, { "sepia", DarkFlag }, { "smyck", DarkFlag }, + { "solarized", DarkFlag }, { "twilight", DarkFlag }, { "white2", DarkFlag }, + { "xvilka", DarkFlag }, { "zenburn", DarkFlag }, + { "cga", LightFlag }, { "cutter", LightFlag }, { "dark", LightFlag }, + { "gb", LightFlag }, { "matrix", LightFlag }, { "tango", LightFlag }, + { "white", LightFlag } }; static const QString DEFAULT_LIGHT_COLOR_THEME = "cutter"; static const QString DEFAULT_DARK_COLOR_THEME = "ayu"; diff --git a/src/widgets/ColorThemeComboBox.cpp b/src/widgets/ColorThemeComboBox.cpp index 50ca6a3b..35b638ec 100644 --- a/src/widgets/ColorThemeComboBox.cpp +++ b/src/widgets/ColorThemeComboBox.cpp @@ -23,6 +23,7 @@ void ColorThemeComboBox::updateFromConfig(bool interfaceThemeChanged) clear(); for (const QString &theme : themes) { if (ThemeWorker().isCustomTheme(theme) + || !Configuration::relevantThemes[theme] || (Configuration::cutterInterfaceThemesList()[curInterfaceThemeIndex].flag & Configuration::relevantThemes[theme])) { addItem(theme); From 80e4269ca3277917c1963f82e9602ed55b161048 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Tue, 14 Sep 2021 21:32:04 +0800 Subject: [PATCH 017/240] Fix Cutter/Rizin API naming (#2755) --- src/core/Cutter.cpp | 52 ++++++++++++------------ src/core/CutterCommon.h | 10 ++--- src/core/MainWindow.cpp | 6 +-- src/dialogs/ArenaInfoDialog.cpp | 14 +++---- src/dialogs/BreakpointsDialog.cpp | 4 +- src/dialogs/CommentsDialog.cpp | 4 +- src/dialogs/EditMethodDialog.cpp | 2 +- src/dialogs/FlagDialog.cpp | 4 +- src/dialogs/GlibcHeapBinsDialog.cpp | 12 +++--- src/dialogs/GlibcHeapInfoDialog.cpp | 16 ++++---- src/dialogs/InitialOptionsDialog.cpp | 2 +- src/dialogs/LinkTypeDialog.cpp | 2 +- src/dialogs/SetToDataDialog.cpp | 4 +- src/dialogs/VersionInfoDialog.cpp | 16 ++++---- src/dialogs/XrefsDialog.cpp | 2 +- src/menus/AddressableItemContextMenu.cpp | 4 +- src/menus/DecompilerContextMenu.cpp | 26 ++++++------ src/menus/DisassemblyContextMenu.cpp | 20 ++++----- src/widgets/BacktraceWidget.cpp | 4 +- src/widgets/BreakpointWidget.cpp | 2 +- src/widgets/CallGraph.cpp | 4 +- src/widgets/ClassesWidget.cpp | 12 +++--- src/widgets/CommentsWidget.cpp | 4 +- src/widgets/ConsoleWidget.cpp | 2 +- src/widgets/Dashboard.cpp | 2 +- src/widgets/DisassemblerGraphView.cpp | 4 +- src/widgets/EntrypointWidget.cpp | 2 +- src/widgets/ExportsWidget.cpp | 4 +- src/widgets/FlagsWidget.cpp | 4 +- src/widgets/FunctionsWidget.cpp | 12 +++--- src/widgets/GlibcHeapWidget.cpp | 6 +-- src/widgets/HeadersWidget.cpp | 2 +- src/widgets/HeapBinsGraphView.cpp | 18 ++++---- src/widgets/HexWidget.cpp | 2 +- src/widgets/ImportsWidget.cpp | 2 +- src/widgets/MemoryMapWidget.cpp | 4 +- src/widgets/RegisterRefsWidget.cpp | 2 +- src/widgets/RelocsWidget.cpp | 2 +- src/widgets/ResourcesWidget.cpp | 2 +- src/widgets/SearchWidget.cpp | 4 +- src/widgets/SectionsWidget.cpp | 14 +++---- src/widgets/SegmentsWidget.cpp | 4 +- src/widgets/SimpleTextGraphView.cpp | 2 +- src/widgets/StackWidget.cpp | 4 +- src/widgets/StringsWidget.cpp | 2 +- src/widgets/SymbolsWidget.cpp | 2 +- src/widgets/TypesWidget.cpp | 2 +- src/widgets/VTablesWidget.cpp | 4 +- src/widgets/VisualNavbar.cpp | 2 +- src/widgets/ZignaturesWidget.cpp | 10 ++--- 50 files changed, 173 insertions(+), 173 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 9c683625..4f21288e 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -686,13 +686,13 @@ bool CutterCore::mapFile(QString path, RVA mapaddr) void CutterCore::renameFunction(const RVA offset, const QString &newName) { - cmdRaw("afn " + newName + " " + RAddressString(offset)); + cmdRaw("afn " + newName + " " + RzAddressString(offset)); emit functionRenamed(offset, newName); } void CutterCore::delFunction(RVA addr) { - cmdRaw("af- " + RAddressString(addr)); + cmdRaw("af- " + RzAddressString(addr)); emit functionsChanged(); } @@ -728,7 +728,7 @@ void CutterCore::delFlag(const QString &name) QString CutterCore::getInstructionBytes(RVA addr) { - return cmdj("aoj @ " + RAddressString(addr)) + return cmdj("aoj @ " + RzAddressString(addr)) .array() .first() .toObject()[RJsonKey::bytes] @@ -737,7 +737,7 @@ QString CutterCore::getInstructionBytes(RVA addr) QString CutterCore::getInstructionOpcode(RVA addr) { - return cmdj("aoj @ " + RAddressString(addr)) + return cmdj("aoj @ " + RzAddressString(addr)) .array() .first() .toObject()[RJsonKey::opcode] @@ -1364,7 +1364,7 @@ RefDescription CutterCore::formatRefDesc(QJsonObject refItem) break; } if (!refItem["value"].isNull()) { - appendVar(desc.ref, RAddressString(refItem["value"].toVariant().toULongLong()), " ", + appendVar(desc.ref, RzAddressString(refItem["value"].toVariant().toULongLong()), " ", ""); } refItem = refItem["ref"].toObject(); @@ -1579,7 +1579,7 @@ QVector CutterCore::getHeapChunks(RVA arena_addr) RzList *chunks = rz_heap_chunks_list(core, m_arena); RzListIter *iter; RzHeapChunkListItem *data; - CutterRListForeach(chunks, iter, RzHeapChunkListItem, data) + CutterRzListForeach(chunks, iter, RzHeapChunkListItem, data) { Chunk chunk; chunk.offset = data->addr; @@ -1607,7 +1607,7 @@ QVector CutterCore::getArenas() RzList *arenas = rz_heap_arenas_list(core); RzListIter *iter; RzArenaListItem *data; - CutterRListForeach(arenas, iter, RzArenaListItem, data) + CutterRzListForeach(arenas, iter, RzArenaListItem, data) { Arena arena; arena.offset = data->addr; @@ -1669,7 +1669,7 @@ QVector CutterCore::getHeapBins(ut64 arena_addr) RzList *tcache_bins = rz_heap_tcache_content(core, arena_addr); RzListIter *iter; RzHeapBin *bin; - CutterRListForeach(tcache_bins, iter, RzHeapBin, bin) + CutterRzListForeach(tcache_bins, iter, RzHeapBin, bin) { if (!bin) { continue; @@ -2458,7 +2458,7 @@ void CutterCore::updateBreakpoint(int index, const BreakpointDescription &config void CutterCore::delBreakpoint(RVA addr) { - cmdRaw("db- " + RAddressString(addr)); + cmdRaw("db- " + RzAddressString(addr)); emit breakpointsChanged(addr); } @@ -2470,13 +2470,13 @@ void CutterCore::delAllBreakpoints() void CutterCore::enableBreakpoint(RVA addr) { - cmdRaw("dbe " + RAddressString(addr)); + cmdRaw("dbe " + RzAddressString(addr)); emit breakpointsChanged(addr); } void CutterCore::disableBreakpoint(RVA addr) { - cmdRaw("dbd " + RAddressString(addr)); + cmdRaw("dbd " + RzAddressString(addr)); emit breakpointsChanged(addr); } @@ -2685,7 +2685,7 @@ QList CutterCore::getSeekHistory() RzListIter *it; RzCoreSeekItem *undo; RzList *list = rz_core_seek_list(core); - CutterRListForeach(list, it, RzCoreSeekItem, undo) { ret << undo->offset; } + CutterRzListForeach(list, it, RzCoreSeekItem, undo) { ret << undo->offset; } return ret; } @@ -2697,7 +2697,7 @@ QStringList CutterCore::getAsmPluginNames() QStringList ret; RzAsmPlugin *ap; - CutterRListForeach(core->rasm->plugins, it, RzAsmPlugin, ap) { ret << ap->name; } + CutterRzListForeach(core->rasm->plugins, it, RzAsmPlugin, ap) { ret << ap->name; } return ret; } @@ -2709,7 +2709,7 @@ QStringList CutterCore::getAnalPluginNames() QStringList ret; RzAnalysisPlugin *ap; - CutterRListForeach(core->analysis->plugins, it, RzAnalysisPlugin, ap) { ret << ap->name; } + CutterRzListForeach(core->analysis->plugins, it, RzAnalysisPlugin, ap) { ret << ap->name; } return ret; } @@ -2792,7 +2792,7 @@ QList CutterCore::getRAsmPluginDescriptions() QList ret; RzAsmPlugin *ap; - CutterRListForeach(core->rasm->plugins, it, RzAsmPlugin, ap) + CutterRzListForeach(core->rasm->plugins, it, RzAsmPlugin, ap) { RzAsmPluginDescription plugin; @@ -2819,7 +2819,7 @@ QList CutterCore::getAllFunctions() RzListIter *iter; RzAnalysisFunction *fcn; - CutterRListForeach(core->analysis->fcns, iter, RzAnalysisFunction, fcn) + CutterRzListForeach(core->analysis->fcns, iter, RzAnalysisFunction, fcn) { FunctionDescription function; function.offset = fcn->addr; @@ -2900,7 +2900,7 @@ QList CutterCore::getAllSymbols() RzBinSymbol *bs; if (core && core->bin && core->bin->cur && core->bin->cur->o) { - CutterRListForeach(core->bin->cur->o->symbols, it, RzBinSymbol, bs) + CutterRzListForeach(core->bin->cur->o->symbols, it, RzBinSymbol, bs) { QString type = QString(bs->bind) + " " + QString(bs->type); SymbolDescription symbol; @@ -2914,7 +2914,7 @@ QList CutterCore::getAllSymbols() /* list entrypoints as symbols too */ int n = 0; RzBinAddr *entry; - CutterRListForeach(core->bin->cur->o->entries, it, RzBinAddr, entry) + CutterRzListForeach(core->bin->cur->o->entries, it, RzBinAddr, entry) { SymbolDescription symbol; symbol.vaddr = entry->vaddr; @@ -3335,7 +3335,7 @@ QList CutterCore::getAnalClassMethods(const QString &cls) ret.reserve(static_cast(meths->len)); RzAnalysisMethod *meth; - CutterRVectorForeach(meths, meth, RzAnalysisMethod) + CutterRzVectorForeach(meths, meth, RzAnalysisMethod) { AnalMethodDescription desc; desc.name = QString::fromUtf8(meth->name); @@ -3360,7 +3360,7 @@ QList CutterCore::getAnalClassBaseClasses(const QStrin ret.reserve(static_cast(bases->len)); RzAnalysisBaseClass *base; - CutterRVectorForeach(bases, base, RzAnalysisBaseClass) + CutterRzVectorForeach(bases, base, RzAnalysisBaseClass) { AnalBaseClassDescription desc; desc.id = QString::fromUtf8(base->id); @@ -3385,7 +3385,7 @@ QList CutterCore::getAnalClassVTables(const QString &cls) acVtables.reserve(static_cast(vtables->len)); RzAnalysisVTable *vtable; - CutterRVectorForeach(vtables, vtable, RzAnalysisVTable) + CutterRzVectorForeach(vtables, vtable, RzAnalysisVTable) { AnalVTableDescription desc; desc.id = QString::fromUtf8(vtable->id); @@ -3528,7 +3528,7 @@ QList CutterCore::getBaseType(RzBaseTypeKind kind, const char * RzBaseType *type; RzListIter *iter; - CutterRListForeach (ts, iter, RzBaseType, type) { + CutterRzListForeach (ts, iter, RzBaseType, type) { TypeDescription exp; exp.type = type->name; @@ -3739,9 +3739,9 @@ QList CutterCore::getXRefsForVariable(QString variableName, boo xref.from = addr; xref.to = addr; if (findWrites) { - xref.from_str = RAddressString(addr); + xref.from_str = RzAddressString(addr); } else { - xref.to_str = RAddressString(addr); + xref.to_str = RzAddressString(addr); } xrefList << xref; } @@ -3775,14 +3775,14 @@ QList CutterCore::getXRefs(RVA addr, bool to, bool whole_functi xref.from = xrefObject[RJsonKey::from].toVariant().toULongLong(); if (!to) { - xref.from_str = RAddressString(xref.from); + xref.from_str = RzAddressString(xref.from); } else { QString fcn = xrefObject[RJsonKey::fcn_name].toString(); if (!fcn.isEmpty()) { RVA fcnAddr = xrefObject[RJsonKey::fcn_addr].toVariant().toULongLong(); xref.from_str = fcn + " + 0x" + QString::number(xref.from - fcnAddr, 16); } else { - xref.from_str = RAddressString(xref.from); + xref.from_str = RzAddressString(xref.from); } } diff --git a/src/core/CutterCommon.h b/src/core/CutterCommon.h index 8f31a5e3..3cbc1941 100644 --- a/src/core/CutterCommon.h +++ b/src/core/CutterCommon.h @@ -15,11 +15,11 @@ #endif // Q_OS_WIN // Rizin list iteration macros -#define CutterRListForeach(list, it, type, x) \ +#define CutterRzListForeach(list, it, type, x) \ if (list) \ for (it = list->head; it && ((x = static_cast(it->data))); it = it->n) -#define CutterRVectorForeach(vec, it, type) \ +#define CutterRzVectorForeach(vec, it, type) \ if ((vec) && (vec)->a) \ for (it = (type *)(vec)->a; \ (char *)it != (char *)(vec)->a + ((vec)->len * (vec)->elem_size); \ @@ -44,17 +44,17 @@ typedef ut64 RVA; */ #define RVA_INVALID RVA_MAX -inline QString RAddressString(RVA addr) +inline QString RzAddressString(RVA addr) { return QString::asprintf("%#010llx", addr); } -inline QString RSizeString(RVA size) +inline QString RzSizeString(RVA size) { return QString::asprintf("%#llx", size); } -inline QString RHexString(RVA size) +inline QString RzHexString(RVA size) { return QString::asprintf("%#llx", size); } diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index 0921293f..9677317a 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -619,7 +619,7 @@ bool MainWindow::openProject(const QString &file) const char *s = rz_project_err_message(err); QString msg = tr("Failed to open project: %1").arg(QString::fromUtf8(s)); RzListIter *it; - CutterRListForeach(res, it, const char, s) { msg += "\n" + QString::fromUtf8(s); } + CutterRzListForeach(res, it, const char, s) { msg += "\n" + QString::fromUtf8(s); } QMessageBox::critical(this, tr("Open Project"), msg); rz_list_free(res); return false; @@ -1134,7 +1134,7 @@ void MainWindow::updateHistoryMenu(QMenu *menu, bool redo) bool history = true; QList actions; - CutterRListForeach(list, it, RzCoreSeekItem, undo) { + CutterRzListForeach(list, it, RzCoreSeekItem, undo) { RzFlagItem *f = rz_flag_get_at(core->flags, undo->offset, true); char *fname = NULL; if (f) { @@ -1151,7 +1151,7 @@ void MainWindow::updateHistoryMenu(QMenu *menu, bool redo) history = false; } if (history != redo || current) { // Include current in both directions - QString addressString = RAddressString(offset); + QString addressString = RzAddressString(offset); QString toolTip = QString("%1 %2").arg(addressString, name); // show non truncated name in tooltip diff --git a/src/dialogs/ArenaInfoDialog.cpp b/src/dialogs/ArenaInfoDialog.cpp index 53634a75..3d389d51 100644 --- a/src/dialogs/ArenaInfoDialog.cpp +++ b/src/dialogs/ArenaInfoDialog.cpp @@ -5,18 +5,18 @@ ArenaInfoDialog::ArenaInfoDialog(Arena &arena, QWidget *parent) : arena(arena), QDialog(parent), ui(new Ui::ArenaInfoDialog) { ui->setupUi(this); - setWindowTitle("Arena @ " + RAddressString(arena.offset)); + setWindowTitle("Arena @ " + RzAddressString(arena.offset)); updateContents(); } void ArenaInfoDialog::updateContents() { - ui->lineEditTop->setText(RAddressString(arena.top)); - ui->lineEditLastRem->setText(RAddressString(arena.last_remainder)); - ui->lineEditNext->setText(RAddressString(arena.next)); - ui->lineEditNextfree->setText(RAddressString(arena.next_free)); - ui->lineEditSysMem->setText(RAddressString(arena.system_mem)); - ui->lineEditMaxMem->setText(RAddressString(arena.max_system_mem)); + ui->lineEditTop->setText(RzAddressString(arena.top)); + ui->lineEditLastRem->setText(RzAddressString(arena.last_remainder)); + ui->lineEditNext->setText(RzAddressString(arena.next)); + ui->lineEditNextfree->setText(RzAddressString(arena.next_free)); + ui->lineEditSysMem->setText(RzAddressString(arena.system_mem)); + ui->lineEditMaxMem->setText(RzAddressString(arena.max_system_mem)); } ArenaInfoDialog::~ArenaInfoDialog() diff --git a/src/dialogs/BreakpointsDialog.cpp b/src/dialogs/BreakpointsDialog.cpp index 979039df..75c5f8b4 100644 --- a/src/dialogs/BreakpointsDialog.cpp +++ b/src/dialogs/BreakpointsDialog.cpp @@ -67,7 +67,7 @@ BreakpointsDialog::BreakpointsDialog(const BreakpointDescription &breakpoint, QW { switch (breakpoint.type) { case BreakpointDescription::Address: - ui->breakpointPosition->setText(RAddressString(breakpoint.addr)); + ui->breakpointPosition->setText(RzAddressString(breakpoint.addr)); break; case BreakpointDescription::Named: ui->breakpointPosition->setText(breakpoint.positionExpression); @@ -102,7 +102,7 @@ BreakpointsDialog::BreakpointsDialog(RVA address, QWidget *parent) : BreakpointsDialog(false, parent) { if (address != RVA_INVALID) { - ui->breakpointPosition->setText(RAddressString(address)); + ui->breakpointPosition->setText(RzAddressString(address)); } refreshOkButton(); } diff --git a/src/dialogs/CommentsDialog.cpp b/src/dialogs/CommentsDialog.cpp index b534fbfb..7a7117ba 100644 --- a/src/dialogs/CommentsDialog.cpp +++ b/src/dialogs/CommentsDialog.cpp @@ -40,9 +40,9 @@ void CommentsDialog::addOrEditComment(RVA offset, QWidget *parent) CommentsDialog c(parent); if (oldComment.isNull() || oldComment.isEmpty()) { - c.setWindowTitle(tr("Add Comment at %1").arg(RAddressString(offset))); + c.setWindowTitle(tr("Add Comment at %1").arg(RzAddressString(offset))); } else { - c.setWindowTitle(tr("Edit Comment at %1").arg(RAddressString(offset))); + c.setWindowTitle(tr("Edit Comment at %1").arg(RzAddressString(offset))); } c.setComment(oldComment); diff --git a/src/dialogs/EditMethodDialog.cpp b/src/dialogs/EditMethodDialog.cpp index eb8d1a0a..fef6251e 100644 --- a/src/dialogs/EditMethodDialog.cpp +++ b/src/dialogs/EditMethodDialog.cpp @@ -89,7 +89,7 @@ void EditMethodDialog::setClass(const QString &className) void EditMethodDialog::setMethod(const AnalMethodDescription &desc) { ui->nameEdit->setText(desc.name); - ui->addressEdit->setText(desc.addr != RVA_INVALID ? RAddressString(desc.addr) : nullptr); + ui->addressEdit->setText(desc.addr != RVA_INVALID ? RzAddressString(desc.addr) : nullptr); if (desc.vtableOffset >= 0) { ui->virtualCheckBox->setChecked(true); diff --git a/src/dialogs/FlagDialog.cpp b/src/dialogs/FlagDialog.cpp index 72f719c5..4e7742e2 100644 --- a/src/dialogs/FlagDialog.cpp +++ b/src/dialogs/FlagDialog.cpp @@ -21,9 +21,9 @@ FlagDialog::FlagDialog(RVA offset, QWidget *parent) ui->sizeEdit->setValidator(size_validator); if (flag) { ui->nameEdit->setText(flag->name); - ui->labelAction->setText(tr("Edit flag at %1").arg(RAddressString(offset))); + ui->labelAction->setText(tr("Edit flag at %1").arg(RzAddressString(offset))); } else { - ui->labelAction->setText(tr("Add flag at %1").arg(RAddressString(offset))); + ui->labelAction->setText(tr("Add flag at %1").arg(RzAddressString(offset))); } // Connect slots diff --git a/src/dialogs/GlibcHeapBinsDialog.cpp b/src/dialogs/GlibcHeapBinsDialog.cpp index 8d0aeede..aea3cdd1 100644 --- a/src/dialogs/GlibcHeapBinsDialog.cpp +++ b/src/dialogs/GlibcHeapBinsDialog.cpp @@ -25,7 +25,7 @@ GlibcHeapBinsDialog::GlibcHeapBinsDialog(RVA m_state, MainWindow *main, QWidget binsModel->reload(); ui->viewBins->resizeColumnsToContents(); graphView = nullptr; - this->setWindowTitle(tr("Bins info for arena @ ") + RAddressString(m_state)); + this->setWindowTitle(tr("Bins info for arena @ ") + RzAddressString(m_state)); } GlibcHeapBinsDialog::~GlibcHeapBinsDialog() @@ -49,9 +49,9 @@ void GlibcHeapBinsDialog::setChainInfo(int index) RzHeapChunkListItem *item; RzList *chunks = binsModel->getChunks(index); QString chainInfo; - CutterRListForeach(chunks, iter, RzHeapChunkListItem, item) + CutterRzListForeach(chunks, iter, RzHeapChunkListItem, item) { - chainInfo += " → " + RAddressString(item->addr); + chainInfo += " → " + RzAddressString(item->addr); } // Add bin message at the end of the list @@ -127,15 +127,15 @@ QVariant BinsModel::data(const QModelIndex &index, int role) const case BinNumColumn: return item->bin_num; case FdColumn: - return (item->fd == 0) ? tr("N/A") : RAddressString(item->fd); + return (item->fd == 0) ? tr("N/A") : RzAddressString(item->fd); case BkColumn: - return (item->bk == 0) ? tr("N/A") : RAddressString(item->bk); + return (item->bk == 0) ? tr("N/A") : RzAddressString(item->bk); case TypeColumn: return tr(item->type); case CountColumn: return rz_list_length(item->chunks); case SizeColumn: - return (item->size == 0) ? tr("N/A") : RHexString(item->size); + return (item->size == 0) ? tr("N/A") : RzHexString(item->size); default: return QVariant(); } diff --git a/src/dialogs/GlibcHeapInfoDialog.cpp b/src/dialogs/GlibcHeapInfoDialog.cpp index c22d6122..a430fbb8 100644 --- a/src/dialogs/GlibcHeapInfoDialog.cpp +++ b/src/dialogs/GlibcHeapInfoDialog.cpp @@ -9,7 +9,7 @@ GlibcHeapInfoDialog::GlibcHeapInfoDialog(RVA offset, QString status, QWidget *pa ui->setupUi(this); // set window title - QString windowTitle = tr("Chunk @ ") + RAddressString(offset); + QString windowTitle = tr("Chunk @ ") + RzAddressString(offset); if (!this->status.isEmpty()) { windowTitle += QString("(" + this->status + ")"); } @@ -34,13 +34,13 @@ void GlibcHeapInfoDialog::updateFields() } // Update the information in the widget - this->ui->baseEdit->setText(RAddressString(offset)); - this->ui->sizeEdit->setText(RHexString(chunk->size)); - this->ui->bkEdit->setText(RAddressString(chunk->bk)); - this->ui->fdEdit->setText(RAddressString(chunk->fd)); - this->ui->bknsEdit->setText(RAddressString(chunk->bk_nextsize)); - this->ui->fdnsEdit->setText(RAddressString(chunk->fd_nextsize)); - this->ui->prevSizeEdit->setText(RHexString(chunk->prev_size)); + this->ui->baseEdit->setText(RzAddressString(offset)); + this->ui->sizeEdit->setText(RzHexString(chunk->size)); + this->ui->bkEdit->setText(RzAddressString(chunk->bk)); + this->ui->fdEdit->setText(RzAddressString(chunk->fd)); + this->ui->bknsEdit->setText(RzAddressString(chunk->bk_nextsize)); + this->ui->fdnsEdit->setText(RzAddressString(chunk->fd_nextsize)); + this->ui->prevSizeEdit->setText(RzHexString(chunk->prev_size)); if (chunk->is_mmapped) { this->ui->rbIM->setChecked(true); } else { diff --git a/src/dialogs/InitialOptionsDialog.cpp b/src/dialogs/InitialOptionsDialog.cpp index 56709b69..be171879 100644 --- a/src/dialogs/InitialOptionsDialog.cpp +++ b/src/dialogs/InitialOptionsDialog.cpp @@ -176,7 +176,7 @@ void InitialOptionsDialog::loadOptions(const InitialOptions &options) } if (options.binLoadAddr != RVA_INVALID) { - ui->entry_loadOffset->setText(RAddressString(options.binLoadAddr)); + ui->entry_loadOffset->setText(RzAddressString(options.binLoadAddr)); } ui->writeCheckBox->setChecked(options.writeEnabled); diff --git a/src/dialogs/LinkTypeDialog.cpp b/src/dialogs/LinkTypeDialog.cpp index 837087fc..fc1c95ea 100644 --- a/src/dialogs/LinkTypeDialog.cpp +++ b/src/dialogs/LinkTypeDialog.cpp @@ -100,7 +100,7 @@ void LinkTypeDialog::on_exprLineEdit_textChanged(const QString &text) { RVA addr = Core()->math(text); if (Core()->isAddressMapped(addr)) { - ui->addressLineEdit->setText(RAddressString(addr)); + ui->addressLineEdit->setText(RzAddressString(addr)); addrValid = true; } else { ui->addressLineEdit->setText(tr("Invalid Address")); diff --git a/src/dialogs/SetToDataDialog.cpp b/src/dialogs/SetToDataDialog.cpp index 92ed96e8..f611e2bb 100644 --- a/src/dialogs/SetToDataDialog.cpp +++ b/src/dialogs/SetToDataDialog.cpp @@ -10,7 +10,7 @@ SetToDataDialog::SetToDataDialog(RVA startAddr, QWidget *parent) validator->setBottom(1); ui->sizeEdit->setValidator(validator); ui->repeatEdit->setValidator(validator); - ui->startAddrLabel->setText(RAddressString(startAddr)); + ui->startAddrLabel->setText(RzAddressString(startAddr)); updateEndAddress(); } @@ -32,7 +32,7 @@ int SetToDataDialog::getItemCount() void SetToDataDialog::updateEndAddress() { RVA endAddr = startAddress + (getItemSize() * getItemCount()); - ui->endAddrLabel->setText(RAddressString(endAddr)); + ui->endAddrLabel->setText(RzAddressString(endAddr)); } void SetToDataDialog::on_sizeEdit_textChanged(const QString &arg1) diff --git a/src/dialogs/VersionInfoDialog.cpp b/src/dialogs/VersionInfoDialog.cpp index 79bda724..9d166bb4 100644 --- a/src/dialogs/VersionInfoDialog.cpp +++ b/src/dialogs/VersionInfoDialog.cpp @@ -43,12 +43,12 @@ void VersionInfoDialog::fillVersionInfo() QTreeWidgetItem *addrItemL = new QTreeWidgetItem(); addrItemL->setText(0, "Address:"); - addrItemL->setText(1, RAddressString(versym["address"].toDouble())); + addrItemL->setText(1, RzAddressString(versym["address"].toDouble())); ui->leftTreeWidget->addTopLevelItem(addrItemL); QTreeWidgetItem *offItemL = new QTreeWidgetItem(); offItemL->setText(0, "Offset:"); - offItemL->setText(1, RAddressString(versym["offset"].toDouble())); + offItemL->setText(1, RzAddressString(versym["offset"].toDouble())); ui->leftTreeWidget->addTopLevelItem(offItemL); QTreeWidgetItem *linkItemL = new QTreeWidgetItem(); @@ -66,7 +66,7 @@ void VersionInfoDialog::fillVersionInfo() for (QJsonValue val : versym["entries"].toArray()) { QJsonObject obj = val.toObject(); QTreeWidgetItem *tempItem = new QTreeWidgetItem(); - tempItem->setText(0, RAddressString(obj["idx"].toDouble())); + tempItem->setText(0, RzAddressString(obj["idx"].toDouble())); tempItem->setText(1, obj["value"].toString()); entriesItemL->addChild(tempItem); } @@ -83,12 +83,12 @@ void VersionInfoDialog::fillVersionInfo() QTreeWidgetItem *addrItemR = new QTreeWidgetItem(); addrItemR->setText(0, "Address:"); - addrItemR->setText(1, RAddressString(verneed["address"].toDouble())); + addrItemR->setText(1, RzAddressString(verneed["address"].toDouble())); ui->rightTreeWidget->addTopLevelItem(addrItemR); QTreeWidgetItem *offItemR = new QTreeWidgetItem(); offItemR->setText(0, "Offset:"); - offItemR->setText(1, RAddressString(verneed["offset"].toDouble())); + offItemR->setText(1, RzAddressString(verneed["offset"].toDouble())); ui->rightTreeWidget->addTopLevelItem(offItemR); QTreeWidgetItem *linkItemR = new QTreeWidgetItem(); @@ -107,7 +107,7 @@ void VersionInfoDialog::fillVersionInfo() QJsonObject parentObj = parentVal.toObject(); QTreeWidgetItem *parentItem = new QTreeWidgetItem(); QString parentString; - parentItem->setText(0, RAddressString(parentObj["idx"].toDouble())); + parentItem->setText(0, RzAddressString(parentObj["idx"].toDouble())); parentString.append("Version: " + QString::number(parentObj["vn_version"].toDouble()) + "\t"); parentString.append("File: " + parentObj["file_name"].toString()); @@ -117,7 +117,7 @@ void VersionInfoDialog::fillVersionInfo() QJsonObject childObj = childVal.toObject(); QTreeWidgetItem *childItem = new QTreeWidgetItem(); QString childString; - childItem->setText(0, RAddressString(childObj["idx"].toDouble())); + childItem->setText(0, RzAddressString(childObj["idx"].toDouble())); childString.append("Name: " + childObj["name"].toString() + "\t"); childString.append("Flags: " + childObj["flags"].toString() + "\t"); childString.append("Version: " + QString::number(childObj["version"].toDouble())); @@ -147,7 +147,7 @@ void VersionInfoDialog::fillVersionInfo() QTreeWidgetItem *tempItem = new QTreeWidgetItem(); tempItem->setText(0, key); if (vs[key].isDouble()) - tempItem->setText(1, RHexString(vs[key].toDouble())); + tempItem->setText(1, RzHexString(vs[key].toDouble())); else tempItem->setText(1, vs[key].toString()); ui->leftTreeWidget->addTopLevelItem(tempItem); diff --git a/src/dialogs/XrefsDialog.cpp b/src/dialogs/XrefsDialog.cpp index 8a9fe3f5..0a721e71 100644 --- a/src/dialogs/XrefsDialog.cpp +++ b/src/dialogs/XrefsDialog.cpp @@ -136,7 +136,7 @@ void XrefsDialog::updatePreview(RVA addr) ui->previewTextEdit->document()->setHtml(disas); // Does it make any sense? - ui->previewTextEdit->find(normalizeAddr(RAddressString(addr)), QTextDocument::FindBackward); + ui->previewTextEdit->find(normalizeAddr(RzAddressString(addr)), QTextDocument::FindBackward); ui->previewTextEdit->moveCursor(QTextCursor::StartOfLine, QTextCursor::MoveAnchor); } diff --git a/src/menus/AddressableItemContextMenu.cpp b/src/menus/AddressableItemContextMenu.cpp index b047067d..0a82a0f7 100644 --- a/src/menus/AddressableItemContextMenu.cpp +++ b/src/menus/AddressableItemContextMenu.cpp @@ -76,7 +76,7 @@ void AddressableItemContextMenu::clearTarget() void AddressableItemContextMenu::onActionCopyAddress() { auto clipboard = QApplication::clipboard(); - clipboard->setText(RAddressString(offset)); + clipboard->setText(RzAddressString(offset)); } void AddressableItemContextMenu::onActionShowXrefs() @@ -85,7 +85,7 @@ void AddressableItemContextMenu::onActionShowXrefs() XrefsDialog dialog(mainWindow, true); QString tmpName = name; if (name.isEmpty()) { - name = RAddressString(offset); + name = RzAddressString(offset); } dialog.fillRefsForAddress(offset, name, wholeFunction); dialog.exec(); diff --git a/src/menus/DecompilerContextMenu.cpp b/src/menus/DecompilerContextMenu.cpp index badc8015..3216abf3 100644 --- a/src/menus/DecompilerContextMenu.cpp +++ b/src/menus/DecompilerContextMenu.cpp @@ -108,7 +108,7 @@ void DecompilerContextMenu::setupBreakpointsInLineMenu() { breakpointsInLineMenu->clear(); for (auto curOffset : this->availableBreakpoints) { - QAction *action = breakpointsInLineMenu->addAction(RAddressString(curOffset)); + QAction *action = breakpointsInLineMenu->addAction(RzAddressString(curOffset)); connect(action, &QAction::triggered, this, [this, curOffset] { BreakpointsDialog::editBreakpoint(Core()->getBreakpointAt(curOffset), this); }); @@ -218,7 +218,7 @@ void DecompilerContextMenu::aboutToShowSlot() } } actionCopyInstructionAddress.setText( - tr("Copy instruction address (%1)").arg(RAddressString(offset))); + tr("Copy instruction address (%1)").arg(RzAddressString(offset))); if (isReference()) { actionCopyReferenceAddress.setVisible(true); RVA referenceAddr = annotationHere->reference.offset; @@ -226,14 +226,14 @@ void DecompilerContextMenu::aboutToShowSlot() if (annotationHere->type == RZ_CODE_ANNOTATION_TYPE_FUNCTION_NAME) { actionCopyReferenceAddress.setText(tr("Copy address of %1 (%2)") .arg(QString(annotationHere->reference.name), - RAddressString(referenceAddr))); + RzAddressString(referenceAddr))); } else if (flagDetails) { actionCopyReferenceAddress.setText( tr("Copy address of %1 (%2)") - .arg(flagDetails->name, RAddressString(referenceAddr))); + .arg(flagDetails->name, RzAddressString(referenceAddr))); } else { actionCopyReferenceAddress.setText( - tr("Copy address (%1)").arg(RAddressString(referenceAddr))); + tr("Copy address (%1)").arg(RzAddressString(referenceAddr))); } } else { actionXRefs.setVisible(false); @@ -371,13 +371,13 @@ void DecompilerContextMenu::actionCopyTriggered() void DecompilerContextMenu::actionCopyInstructionAddressTriggered() { QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(RAddressString(offset)); + clipboard->setText(RzAddressString(offset)); } void DecompilerContextMenu::actionCopyReferenceAddressTriggered() { QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(RAddressString(annotationHere->reference.offset)); + clipboard->setText(RzAddressString(annotationHere->reference.offset)); } void DecompilerContextMenu::actionAddCommentTriggered() @@ -404,7 +404,7 @@ void DecompilerContextMenu::actionRenameThingHereTriggered() RzAnalysisFunction *func = Core()->functionAt(func_addr); if (func == NULL) { QString function_name = QInputDialog::getText( - this, tr("Define this function at %2").arg(RAddressString(func_addr)), + this, tr("Define this function at %2").arg(RzAddressString(func_addr)), tr("Function name:"), QLineEdit::Normal, currentName, &ok); if (ok && !function_name.isEmpty()) { Core()->createFunctionAt(func_addr, function_name); @@ -483,7 +483,7 @@ void DecompilerContextMenu::actionXRefsTriggered() XrefsDialog dialog(mainWindow); QString displayString = (annotationHere->type == RZ_CODE_ANNOTATION_TYPE_FUNCTION_NAME) ? QString(annotationHere->reference.name) - : RAddressString(annotationHere->reference.offset); + : RzAddressString(annotationHere->reference.offset); dialog.fillRefsForAddress(annotationHere->reference.offset, displayString, false); dialog.exec(); } @@ -519,13 +519,13 @@ void DecompilerContextMenu::actionAdvancedBreakpointTriggered() void DecompilerContextMenu::actionContinueUntilTriggered() { - Core()->continueUntilDebug(RAddressString(offset)); + Core()->continueUntilDebug(RzAddressString(offset)); } void DecompilerContextMenu::actionSetPCTriggered() { QString progCounterName = Core()->getRegisterName("PC"); - Core()->setRegister(progCounterName, RAddressString(offset).toUpper()); + Core()->setRegister(progCounterName, RzAddressString(offset).toUpper()); } // Set up menus @@ -574,13 +574,13 @@ void DecompilerContextMenu::updateTargetMenuActions() if (flagDetails) { name = tr("Show %1 in").arg(flagDetails->name); } else { - name = tr("Show %1 in").arg(RAddressString(annotationHere->reference.offset)); + name = tr("Show %1 in").arg(RzAddressString(annotationHere->reference.offset)); } } else if (annotationHere->type == RZ_CODE_ANNOTATION_TYPE_FUNCTION_NAME) { menu = mainWindow->createShowInMenu(this, annotationHere->reference.offset, MainWindow::AddressTypeHint::Function); name = tr("%1 (%2)").arg(QString(annotationHere->reference.name), - RAddressString(annotationHere->reference.offset)); + RzAddressString(annotationHere->reference.offset)); } auto action = new QAction(name, this); showTargetMenuActions.append(action); diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 7d1fd5d6..57c63537 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -409,7 +409,7 @@ void DisassemblyContextMenu::buildRenameMenu(ThingUsedHere *tuh) actionDeleteFlag.setVisible(false); if (tuh->type == ThingUsedHere::Type::Address) { doRenameAction = RENAME_ADD_FLAG; - doRenameInfo.name = RAddressString(tuh->offset); + doRenameInfo.name = RzAddressString(tuh->offset); doRenameInfo.addr = tuh->offset; actionRename.setText(tr("Add flag at %1 (used here)").arg(doRenameInfo.name)); } else if (tuh->type == ThingUsedHere::Type::Function) { @@ -698,7 +698,7 @@ void DisassemblyContextMenu::on_actionEditInstruction_triggered() return; } EditInstructionDialog e(EDIT_TEXT, this); - e.setWindowTitle(tr("Edit Instruction at %1").arg(RAddressString(offset))); + e.setWindowTitle(tr("Edit Instruction at %1").arg(RzAddressString(offset))); QString oldInstructionOpcode = Core()->getInstructionOpcode(offset); QString oldInstructionBytes = Core()->getInstructionBytes(offset); @@ -725,7 +725,7 @@ void DisassemblyContextMenu::showReverseJmpQuery() { QString type; - QJsonArray array = Core()->cmdj("pdj 1 @ " + RAddressString(offset)).array(); + QJsonArray array = Core()->cmdj("pdj 1 @ " + RzAddressString(offset)).array(); if (array.isEmpty()) { return; } @@ -752,7 +752,7 @@ void DisassemblyContextMenu::on_actionEditBytes_triggered() return; } EditInstructionDialog e(EDIT_BYTES, this); - e.setWindowTitle(tr("Edit Bytes at %1").arg(RAddressString(offset))); + e.setWindowTitle(tr("Edit Bytes at %1").arg(RzAddressString(offset))); QString oldBytes = Core()->getInstructionBytes(offset); e.setInstruction(oldBytes); @@ -773,7 +773,7 @@ void DisassemblyContextMenu::on_actionCopy_triggered() void DisassemblyContextMenu::on_actionCopyAddr_triggered() { QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(RAddressString(offset)); + clipboard->setText(RzAddressString(offset)); } void DisassemblyContextMenu::on_actionAddBreakpoint_triggered() @@ -793,13 +793,13 @@ void DisassemblyContextMenu::on_actionAdvancedBreakpoint_triggered() void DisassemblyContextMenu::on_actionContinueUntil_triggered() { - Core()->continueUntilDebug(RAddressString(offset)); + Core()->continueUntilDebug(RzAddressString(offset)); } void DisassemblyContextMenu::on_actionSetPC_triggered() { QString progCounterName = Core()->getRegisterName("PC"); - Core()->setRegister(progCounterName, RAddressString(offset).toUpper()); + Core()->setRegister(progCounterName, RzAddressString(offset).toUpper()); } void DisassemblyContextMenu::on_actionAddComment_triggered() @@ -823,7 +823,7 @@ void DisassemblyContextMenu::on_actionAnalyzeFunction_triggered() // Create dialog QString functionName = - QInputDialog::getText(this, tr("New function at %1").arg(RAddressString(offset)), + QInputDialog::getText(this, tr("New function at %1").arg(RzAddressString(offset)), tr("Function name:"), QLineEdit::Normal, name, &ok); // If user accepted @@ -887,7 +887,7 @@ void DisassemblyContextMenu::on_actionSetFunctionVarTypes_triggered() void DisassemblyContextMenu::on_actionXRefs_triggered() { XrefsDialog dialog(mainWindow); - dialog.fillRefsForAddress(offset, RAddressString(offset), false); + dialog.fillRefsForAddress(offset, RzAddressString(offset), false); dialog.exec(); } @@ -990,7 +990,7 @@ void DisassemblyContextMenu::on_actionLinkType_triggered() { LinkTypeDialog dialog(mainWindow); if (!dialog.setDefaultAddress(curHighlightedWord)) { - dialog.setDefaultAddress(RAddressString(offset)); + dialog.setDefaultAddress(RzAddressString(offset)); } dialog.exec(); } diff --git a/src/widgets/BacktraceWidget.cpp b/src/widgets/BacktraceWidget.cpp index bd92b3e7..793813d7 100644 --- a/src/widgets/BacktraceWidget.cpp +++ b/src/widgets/BacktraceWidget.cpp @@ -48,8 +48,8 @@ void BacktraceWidget::setBacktraceGrid() int i = 0; for (const QJsonValue &value : backtraceValues) { QJsonObject backtraceItem = value.toObject(); - QString progCounter = RAddressString(backtraceItem["pc"].toVariant().toULongLong()); - QString stackPointer = RAddressString(backtraceItem["sp"].toVariant().toULongLong()); + QString progCounter = RzAddressString(backtraceItem["pc"].toVariant().toULongLong()); + QString stackPointer = RzAddressString(backtraceItem["sp"].toVariant().toULongLong()); int frameSize = backtraceItem["frame_size"].toVariant().toInt(); QString funcName = backtraceItem["fname"].toString(); QString desc = backtraceItem["desc"].toString(); diff --git a/src/widgets/BreakpointWidget.cpp b/src/widgets/BreakpointWidget.cpp index 70d5b1f4..ceb5636d 100644 --- a/src/widgets/BreakpointWidget.cpp +++ b/src/widgets/BreakpointWidget.cpp @@ -55,7 +55,7 @@ QVariant BreakpointModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { case AddrColumn: - return RAddressString(breakpoint.addr); + return RzAddressString(breakpoint.addr); case NameColumn: return breakpoint.name; case TypeColumn: diff --git a/src/widgets/CallGraph.cpp b/src/widgets/CallGraph.cpp index f1b5a955..2bd16b73 100644 --- a/src/widgets/CallGraph.cpp +++ b/src/widgets/CallGraph.cpp @@ -45,7 +45,7 @@ void CallGraphView::showExportDialog() if (global) { defaultName = "global_callgraph"; } else { - defaultName = QString("callgraph_%1").arg(RAddressString(address)); + defaultName = QString("callgraph_%1").arg(RzAddressString(address)); } showExportGraphDialog(defaultName, global ? "agC" : "agc", address); } @@ -115,7 +115,7 @@ void CallGraphView::loadCurrentGraph() } } if (blockContent.empty() && !global) { - addBlock({}, RAddressString(address), address); + addBlock({}, RzAddressString(address), address); } addressMapping.clear(); diff --git a/src/widgets/ClassesWidget.cpp b/src/widgets/ClassesWidget.cpp index ade8af4d..4378d064 100644 --- a/src/widgets/ClassesWidget.cpp +++ b/src/widgets/ClassesWidget.cpp @@ -120,7 +120,7 @@ QVariant BinClassesModel::data(const QModelIndex &index, int role) const case TYPE: return tr("method"); case OFFSET: - return meth->addr == RVA_INVALID ? QString() : RAddressString(meth->addr); + return meth->addr == RVA_INVALID ? QString() : RzAddressString(meth->addr); case VTABLE: return meth->vtableOffset < 0 ? QString() : QString("+%1").arg(meth->vtableOffset); default: @@ -144,7 +144,7 @@ QVariant BinClassesModel::data(const QModelIndex &index, int role) const case TYPE: return tr("field"); case OFFSET: - return field->addr == RVA_INVALID ? QString() : RAddressString(field->addr); + return field->addr == RVA_INVALID ? QString() : RzAddressString(field->addr); default: return QVariant(); } @@ -186,9 +186,9 @@ QVariant BinClassesModel::data(const QModelIndex &index, int role) const case TYPE: return tr("class"); case OFFSET: - return cls->addr == RVA_INVALID ? QString() : RAddressString(cls->addr); + return cls->addr == RVA_INVALID ? QString() : RzAddressString(cls->addr); case VTABLE: - return cls->vtableAddr == RVA_INVALID ? QString() : RAddressString(cls->vtableAddr); + return cls->vtableAddr == RVA_INVALID ? QString() : RzAddressString(cls->vtableAddr); default: return QVariant(); } @@ -457,7 +457,7 @@ QVariant AnalClassesModel::data(const QModelIndex &index, int role) const case TYPE: return tr("method"); case OFFSET: - return meth.addr == RVA_INVALID ? QString() : RAddressString(meth.addr); + return meth.addr == RVA_INVALID ? QString() : RzAddressString(meth.addr); case VTABLE: return meth.vtableOffset < 0 ? QString() : QString("+%1").arg(meth.vtableOffset); @@ -493,7 +493,7 @@ QVariant AnalClassesModel::data(const QModelIndex &index, int role) const case TYPE: return tr("vtable"); case OFFSET: - return RAddressString(vtable.addr); + return RzAddressString(vtable.addr); default: return QVariant(); } diff --git a/src/widgets/CommentsWidget.cpp b/src/widgets/CommentsWidget.cpp index 6fc98b3c..ddb4bbb9 100644 --- a/src/widgets/CommentsWidget.cpp +++ b/src/widgets/CommentsWidget.cpp @@ -114,7 +114,7 @@ QVariant CommentsModel::data(const QModelIndex &index, int role) const if (isSubnode) { switch (index.column()) { case OffsetNestedColumn: - return RAddressString(comment.offset); + return RzAddressString(comment.offset); case CommentNestedColumn: return comment.name; default: @@ -126,7 +126,7 @@ QVariant CommentsModel::data(const QModelIndex &index, int role) const } else { switch (index.column()) { case CommentsModel::OffsetColumn: - return RAddressString(comment.offset); + return RzAddressString(comment.offset); case CommentsModel::FunctionColumn: return Core()->cmdFunctionAt(comment.offset); case CommentsModel::CommentColumn: diff --git a/src/widgets/ConsoleWidget.cpp b/src/widgets/ConsoleWidget.cpp index 14d282cf..92638534 100644 --- a/src/widgets/ConsoleWidget.cpp +++ b/src/widgets/ConsoleWidget.cpp @@ -223,7 +223,7 @@ void ConsoleWidget::executeCommand(const QString &command) } ui->rzInputLineEdit->setEnabled(false); - QString cmd_line = "[" + RAddressString(Core()->getOffset()) + "]> " + command; + QString cmd_line = "[" + RzAddressString(Core()->getOffset()) + "]> " + command; addOutput(cmd_line); RVA oldOffset = Core()->getOffset(); diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index 781e9015..6f547e4b 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -62,7 +62,7 @@ void Dashboard::updateContents() setPlainText(this->ui->relroEdit, "N/A"); } - setPlainText(this->ui->baddrEdit, RAddressString(item2["baddr"].toVariant().toULongLong())); + setPlainText(this->ui->baddrEdit, RzAddressString(item2["baddr"].toVariant().toULongLong())); // set booleans setBool(this->ui->vaEdit, item2, "va"); diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index 5d43d0cb..9df66ac4 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -179,7 +179,7 @@ void DisassemblerGraphView::loadCurrentGraph() RzAnalysisFunction *fcn = Core()->functionIn(seekable->getOffset()); if (fcn) { currentFcnAddr = fcn->addr; - QJsonDocument functionsDoc = Core()->cmdj("agJ " + RAddressString(fcn->addr)); + QJsonDocument functionsDoc = Core()->cmdj("agJ " + RzAddressString(fcn->addr)); functions = functionsDoc.array(); } @@ -236,7 +236,7 @@ void DisassemblerGraphView::loadCurrentGraph() db.entry = block_entry; if (Config()->getGraphBlockEntryOffset()) { // QColor(0,0,0,0) is transparent - db.header_text = Text("[" + RAddressString(db.entry) + "]", ConfigColor("offset"), + db.header_text = Text("[" + RzAddressString(db.entry) + "]", ConfigColor("offset"), QColor(0, 0, 0, 0)); } db.true_path = RVA_INVALID; diff --git a/src/widgets/EntrypointWidget.cpp b/src/widgets/EntrypointWidget.cpp index a331d1b8..5c78a371 100644 --- a/src/widgets/EntrypointWidget.cpp +++ b/src/widgets/EntrypointWidget.cpp @@ -29,7 +29,7 @@ void EntrypointWidget::fillEntrypoint() ui->entrypointTreeWidget->clear(); for (const EntrypointDescription &i : Core()->getAllEntrypoint()) { QTreeWidgetItem *item = new QTreeWidgetItem(); - item->setText(0, RAddressString(i.vaddr)); + item->setText(0, RzAddressString(i.vaddr)); item->setText(1, i.type); item->setData(0, Qt::UserRole, QVariant::fromValue(i)); ui->entrypointTreeWidget->addTopLevelItem(item); diff --git a/src/widgets/ExportsWidget.cpp b/src/widgets/ExportsWidget.cpp index 2f7884a8..7a5fb646 100644 --- a/src/widgets/ExportsWidget.cpp +++ b/src/widgets/ExportsWidget.cpp @@ -32,9 +32,9 @@ QVariant ExportsModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { case ExportsModel::OffsetColumn: - return RAddressString(exp.vaddr); + return RzAddressString(exp.vaddr); case ExportsModel::SizeColumn: - return RSizeString(exp.size); + return RzSizeString(exp.size); case ExportsModel::TypeColumn: return exp.type; case ExportsModel::NameColumn: diff --git a/src/widgets/FlagsWidget.cpp b/src/widgets/FlagsWidget.cpp index 12c775c3..75b72063 100644 --- a/src/widgets/FlagsWidget.cpp +++ b/src/widgets/FlagsWidget.cpp @@ -36,9 +36,9 @@ QVariant FlagsModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { case SIZE: - return RSizeString(flag.size); + return RzSizeString(flag.size); case OFFSET: - return RAddressString(flag.offset); + return RzAddressString(flag.offset); case NAME: return flag.name; case REALNAME: diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index b0e72d6c..760a7487 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -130,18 +130,18 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const if (subnode) { switch (index.row()) { case 0: - return tr("Offset: %1").arg(RAddressString(function.offset)); + return tr("Offset: %1").arg(RzAddressString(function.offset)); case 1: - return tr("Size: %1").arg(RSizeString(function.linearSize)); + return tr("Size: %1").arg(RzSizeString(function.linearSize)); case 2: return tr("Import: %1") .arg(functionIsImport(function.offset) ? tr("true") : tr("false")); case 3: - return tr("Nargs: %1").arg(RSizeString(function.nargs)); + return tr("Nargs: %1").arg(RzSizeString(function.nargs)); case 4: - return tr("Nbbs: %1").arg(RSizeString(function.nbbs)); + return tr("Nbbs: %1").arg(RzSizeString(function.nbbs)); case 5: - return tr("Nlocals: %1").arg(RSizeString(function.nlocals)); + return tr("Nlocals: %1").arg(RzSizeString(function.nlocals)); case 6: return tr("Call type: %1").arg(function.calltype); case 7: @@ -164,7 +164,7 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const case ImportColumn: return functionIsImport(function.offset) ? tr("true") : tr("false"); case OffsetColumn: - return RAddressString(function.offset); + return RzAddressString(function.offset); case NargsColumn: return QString::number(function.nargs); case NlocalsColumn: diff --git a/src/widgets/GlibcHeapWidget.cpp b/src/widgets/GlibcHeapWidget.cpp index 990ee210..47278fa6 100644 --- a/src/widgets/GlibcHeapWidget.cpp +++ b/src/widgets/GlibcHeapWidget.cpp @@ -66,7 +66,7 @@ void GlibcHeapWidget::updateArenas() // add the new arenas to the arena selector for (auto &arena : arenas) { - arenaSelectorView->addItem(RAddressString(arena.offset) + arenaSelectorView->addItem(RzAddressString(arena.offset) + QString(" (" + arena.type + " Arena)")); } @@ -138,9 +138,9 @@ QVariant GlibcHeapModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { case OffsetColumn: - return RAddressString(item.offset); + return RzAddressString(item.offset); case SizeColumn: - return RHexString(item.size); + return RzHexString(item.size); case StatusColumn: return item.status; default: diff --git a/src/widgets/HeadersWidget.cpp b/src/widgets/HeadersWidget.cpp index 80056b4e..fc4c4dda 100644 --- a/src/widgets/HeadersWidget.cpp +++ b/src/widgets/HeadersWidget.cpp @@ -29,7 +29,7 @@ QVariant HeadersModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { case OffsetColumn: - return RAddressString(header.vaddr); + return RzAddressString(header.vaddr); case NameColumn: return header.name; case ValueColumn: diff --git a/src/widgets/HeapBinsGraphView.cpp b/src/widgets/HeapBinsGraphView.cpp index 97ae534d..320938ee 100644 --- a/src/widgets/HeapBinsGraphView.cpp +++ b/src/widgets/HeapBinsGraphView.cpp @@ -36,7 +36,7 @@ void HeapBinsGraphView::loadCurrentGraph() || QString(heapBin->type) == QString("Tcache"); // store info about the chunks in a vector for easy access - CutterRListForeach(heapBin->chunks, iter, RzHeapChunkListItem, item) + CutterRzListForeach(heapBin->chunks, iter, RzHeapChunkListItem, item) { GraphHeapChunk graphHeapChunk; graphHeapChunk.addr = item->addr; @@ -44,12 +44,12 @@ void HeapBinsGraphView::loadCurrentGraph() if (!chunkInfo) { break; } - QString content = "Chunk @ " + RAddressString(chunkInfo->addr) + "\nSize: " - + RHexString(chunkInfo->size) + "\nFd: " + RAddressString(chunkInfo->fd); + QString content = "Chunk @ " + RzAddressString(chunkInfo->addr) + "\nSize: " + + RzHexString(chunkInfo->size) + "\nFd: " + RzAddressString(chunkInfo->fd); // fastbins lack bk pointer if (!singleLinkedBin) { - content += "\nBk: " + RAddressString(chunkInfo->bk); + content += "\nBk: " + RzAddressString(chunkInfo->bk); } graphHeapChunk.fd = chunkInfo->fd; graphHeapChunk.bk = chunkInfo->bk; @@ -79,9 +79,9 @@ void HeapBinsGraphView::display_single_linked_list(QVector chunk gbBin.edges.emplace_back(heapBin->fd); QString content = tr(heapBin->type) + tr("bin ") + QString::number(heapBin->bin_num); if (tcache) { - content += "\nEntry: " + RAddressString(heapBin->fd); + content += "\nEntry: " + RzAddressString(heapBin->fd); } else { - content += "\nFd: " + RAddressString(heapBin->fd); + content += "\nFd: " + RzAddressString(heapBin->fd); } addBlock(gbBin, content); @@ -120,9 +120,9 @@ void HeapBinsGraphView::display_double_linked_list(QVector chunk gbBin.edges.emplace_back(heapBin->fd); gbBin.edges.emplace_back(heapBin->bk); QString content = tr(heapBin->type) + tr("bin ") + QString::number(heapBin->bin_num) + tr(" @ ") - + RAddressString(heapBin->addr); - content += "\nFd: " + RAddressString(heapBin->fd); - content += "\nBk: " + RAddressString(heapBin->bk); + + RzAddressString(heapBin->addr); + content += "\nFd: " + RzAddressString(heapBin->fd); + content += "\nBk: " + RzAddressString(heapBin->bk); addBlock(gbBin, content, heapBin->addr); diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index cfcbecd0..914cb6c3 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -682,7 +682,7 @@ void HexWidget::copyAddress() addr = selection.start(); } QClipboard *clipboard = QApplication::clipboard(); - clipboard->setText(RAddressString(addr)); + clipboard->setText(RzAddressString(addr)); } void HexWidget::onRangeDialogAccepted() diff --git a/src/widgets/ImportsWidget.cpp b/src/widgets/ImportsWidget.cpp index 49174c8d..4c36439c 100644 --- a/src/widgets/ImportsWidget.cpp +++ b/src/widgets/ImportsWidget.cpp @@ -38,7 +38,7 @@ QVariant ImportsModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { case ImportsModel::AddressColumn: - return RAddressString(import.plt); + return RzAddressString(import.plt); case ImportsModel::TypeColumn: return import.type; case ImportsModel::SafetyColumn: diff --git a/src/widgets/MemoryMapWidget.cpp b/src/widgets/MemoryMapWidget.cpp index 7912a0de..de7e0ded 100644 --- a/src/widgets/MemoryMapWidget.cpp +++ b/src/widgets/MemoryMapWidget.cpp @@ -30,9 +30,9 @@ QVariant MemoryMapModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { case AddrStartColumn: - return RAddressString(memoryMap.addrStart); + return RzAddressString(memoryMap.addrStart); case AddrEndColumn: - return RAddressString(memoryMap.addrEnd); + return RzAddressString(memoryMap.addrEnd); case NameColumn: return memoryMap.name; case PermColumn: diff --git a/src/widgets/RegisterRefsWidget.cpp b/src/widgets/RegisterRefsWidget.cpp index 3718bec1..adfd67af 100644 --- a/src/widgets/RegisterRefsWidget.cpp +++ b/src/widgets/RegisterRefsWidget.cpp @@ -189,7 +189,7 @@ void RegisterRefsWidget::refreshRegisterRef() for (const QJsonObject ® : regRefs) { RegisterRefDescription desc; - desc.value = RAddressString(reg["value"].toVariant().toULongLong()); + desc.value = RzAddressString(reg["value"].toVariant().toULongLong()); desc.reg = reg["name"].toVariant().toString(); desc.refDesc = Core()->formatRefDesc(reg["ref"].toObject()); diff --git a/src/widgets/RelocsWidget.cpp b/src/widgets/RelocsWidget.cpp index f23d971e..eb4a2c18 100644 --- a/src/widgets/RelocsWidget.cpp +++ b/src/widgets/RelocsWidget.cpp @@ -25,7 +25,7 @@ QVariant RelocsModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { case RelocsModel::VAddrColumn: - return RAddressString(reloc.vaddr); + return RzAddressString(reloc.vaddr); case RelocsModel::TypeColumn: return reloc.type; case RelocsModel::NameColumn: diff --git a/src/widgets/ResourcesWidget.cpp b/src/widgets/ResourcesWidget.cpp index ec4e694f..a9d41298 100644 --- a/src/widgets/ResourcesWidget.cpp +++ b/src/widgets/ResourcesWidget.cpp @@ -29,7 +29,7 @@ QVariant ResourcesModel::data(const QModelIndex &index, int role) const case NAME: return res.name; case VADDR: - return RAddressString(res.vaddr); + return RzAddressString(res.vaddr); case INDEX: return QString::number(res.index); case TYPE: diff --git a/src/widgets/SearchWidget.cpp b/src/widgets/SearchWidget.cpp index b4d38589..ae3c419b 100644 --- a/src/widgets/SearchWidget.cpp +++ b/src/widgets/SearchWidget.cpp @@ -57,9 +57,9 @@ QVariant SearchModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { case OFFSET: - return RAddressString(exp.offset); + return RzAddressString(exp.offset); case SIZE: - return RSizeString(exp.size); + return RzSizeString(exp.size); case CODE: return exp.code; case DATA: diff --git a/src/widgets/SectionsWidget.cpp b/src/widgets/SectionsWidget.cpp index ef5a170d..548b997d 100644 --- a/src/widgets/SectionsWidget.cpp +++ b/src/widgets/SectionsWidget.cpp @@ -57,13 +57,13 @@ QVariant SectionsModel::data(const QModelIndex &index, int role) const case SectionsModel::NameColumn: return section.name; case SectionsModel::SizeColumn: - return RSizeString(section.size); + return RzSizeString(section.size); case SectionsModel::AddressColumn: - return RAddressString(section.vaddr); + return RzAddressString(section.vaddr); case SectionsModel::EndAddressColumn: - return RAddressString(section.vaddr + section.vsize); + return RzAddressString(section.vaddr + section.vsize); case SectionsModel::VirtualSizeColumn: - return RSizeString(section.vsize); + return RzSizeString(section.vsize); case SectionsModel::PermissionsColumn: return section.perm; case SectionsModel::EntropyColumn: @@ -368,8 +368,8 @@ void AbstractAddrDock::updateDock() rect->setBrush(QBrush(idx.data(Qt::DecorationRole).value())); addrDockScene->addItem(rect); - addTextItem(textColor, QPoint(0, y), RAddressString(addr)); - addTextItem(textColor, QPoint(rectOffset, y), RSizeString(size)); + addTextItem(textColor, QPoint(0, y), RzAddressString(addr)); + addTextItem(textColor, QPoint(rectOffset, y), RzSizeString(size)); addTextItem(textColor, QPoint(rectOffset + rectWidth, y), name); addrDockScene->namePosYMap[name] = y; @@ -458,7 +458,7 @@ void AddrDockScene::mousePressEvent(QGraphicsSceneMouseEvent *event) { RVA addr = getAddrFromPos((int)event->scenePos().y(), false); if (addr != RVA_INVALID) { - QToolTip::showText(event->screenPos(), RAddressString(addr)); + QToolTip::showText(event->screenPos(), RzAddressString(addr)); if (event->buttons() & Qt::LeftButton) { RVA seekAddr = getAddrFromPos((int)event->scenePos().y(), true); disableCenterOn = true; diff --git a/src/widgets/SegmentsWidget.cpp b/src/widgets/SegmentsWidget.cpp index a2a35938..526aaea6 100644 --- a/src/widgets/SegmentsWidget.cpp +++ b/src/widgets/SegmentsWidget.cpp @@ -51,9 +51,9 @@ QVariant SegmentsModel::data(const QModelIndex &index, int role) const case SegmentsModel::SizeColumn: return QString::number(segment.size); case SegmentsModel::AddressColumn: - return RAddressString(segment.vaddr); + return RzAddressString(segment.vaddr); case SegmentsModel::EndAddressColumn: - return RAddressString(segment.vaddr + segment.size); + return RzAddressString(segment.vaddr + segment.size); case SegmentsModel::PermColumn: return segment.perm; case SegmentsModel::CommentColumn: diff --git a/src/widgets/SimpleTextGraphView.cpp b/src/widgets/SimpleTextGraphView.cpp index 1a765619..ad4c5deb 100644 --- a/src/widgets/SimpleTextGraphView.cpp +++ b/src/widgets/SimpleTextGraphView.cpp @@ -222,7 +222,7 @@ void SimpleTextGraphView::blockHelpEvent(GraphView::GraphBlock &block, QHelpEven QPoint /*pos*/) { if (haveAddresses) { - QToolTip::showText(event->globalPos(), RAddressString(blockContent[block.entry].address)); + QToolTip::showText(event->globalPos(), RzAddressString(blockContent[block.entry].address)); } } diff --git a/src/widgets/StackWidget.cpp b/src/widgets/StackWidget.cpp index 88ed9a87..fd68db29 100644 --- a/src/widgets/StackWidget.cpp +++ b/src/widgets/StackWidget.cpp @@ -153,7 +153,7 @@ void StackModel::reload() Item item; item.offset = stackItem["addr"].toVariant().toULongLong(); - item.value = RAddressString(stackItem["value"].toVariant().toULongLong()); + item.value = RzAddressString(stackItem["value"].toVariant().toULongLong()); item.refDesc = Core()->formatRefDesc(stackItem["ref"].toObject()); values.push_back(item); @@ -182,7 +182,7 @@ QVariant StackModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { case OffsetColumn: - return RAddressString(item.offset); + return RzAddressString(item.offset); case ValueColumn: return item.value; case DescriptionColumn: diff --git a/src/widgets/StringsWidget.cpp b/src/widgets/StringsWidget.cpp index 290c3af7..ab71211a 100644 --- a/src/widgets/StringsWidget.cpp +++ b/src/widgets/StringsWidget.cpp @@ -35,7 +35,7 @@ QVariant StringsModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { case StringsModel::OffsetColumn: - return RAddressString(str.vaddr); + return RzAddressString(str.vaddr); case StringsModel::StringColumn: return str.string; case StringsModel::TypeColumn: diff --git a/src/widgets/SymbolsWidget.cpp b/src/widgets/SymbolsWidget.cpp index 0a19a473..bbc88e8d 100644 --- a/src/widgets/SymbolsWidget.cpp +++ b/src/widgets/SymbolsWidget.cpp @@ -32,7 +32,7 @@ QVariant SymbolsModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { case SymbolsModel::AddressColumn: - return RAddressString(symbol.vaddr); + return RzAddressString(symbol.vaddr); case SymbolsModel::TypeColumn: return QString("%1 %2").arg(symbol.bind, symbol.type).trimmed(); case SymbolsModel::NameColumn: diff --git a/src/widgets/TypesWidget.cpp b/src/widgets/TypesWidget.cpp index c9963c79..e5c7a8ec 100644 --- a/src/widgets/TypesWidget.cpp +++ b/src/widgets/TypesWidget.cpp @@ -336,7 +336,7 @@ void TypesWidget::on_actionLink_Type_To_Address_triggered() if (index.isValid()) { TypeDescription t = index.data(TypesModel::TypeDescriptionRole).value(); dialog.setDefaultType(t.type); - dialog.setDefaultAddress(RAddressString(Core()->getOffset())); + dialog.setDefaultAddress(RzAddressString(Core()->getOffset())); dialog.exec(); } } diff --git a/src/widgets/VTablesWidget.cpp b/src/widgets/VTablesWidget.cpp index df3946d4..eb7437df 100644 --- a/src/widgets/VTablesWidget.cpp +++ b/src/widgets/VTablesWidget.cpp @@ -47,7 +47,7 @@ QVariant VTableModel::data(const QModelIndex &index, int role) const case NAME: return res.name; case ADDRESS: - return RAddressString(res.addr); + return RzAddressString(res.addr); } break; case VTableDescriptionRole: @@ -62,7 +62,7 @@ QVariant VTableModel::data(const QModelIndex &index, int role) const case NAME: return tr("VTable") + " " + QString::number(index.row() + 1); case ADDRESS: - return RAddressString(vtables->at(index.row()).addr); + return RzAddressString(vtables->at(index.row()).addr); } break; case VTableDescriptionRole: { diff --git a/src/widgets/VisualNavbar.cpp b/src/widgets/VisualNavbar.cpp index 755014e1..1f125b26 100644 --- a/src/widgets/VisualNavbar.cpp +++ b/src/widgets/VisualNavbar.cpp @@ -297,7 +297,7 @@ QList VisualNavbar::sectionsForAddress(RVA address) QString VisualNavbar::toolTipForAddress(RVA address) { - QString ret = "Address: " + RAddressString(address); + QString ret = "Address: " + RzAddressString(address); // Don't append sections when a debug task is in progress to avoid freezing the interface if (Core()->isDebugTaskInProgress()) { diff --git a/src/widgets/ZignaturesWidget.cpp b/src/widgets/ZignaturesWidget.cpp index a1b2167a..222a4d09 100644 --- a/src/widgets/ZignaturesWidget.cpp +++ b/src/widgets/ZignaturesWidget.cpp @@ -29,7 +29,7 @@ QVariant ZignaturesModel::data(const QModelIndex &index, int role) const case Qt::DisplayRole: switch (index.column()) { case OffsetColumn: - return RAddressString(zignature.offset); + return RzAddressString(zignature.offset); case NameColumn: return zignature.name; case ValueColumn: @@ -42,10 +42,10 @@ QVariant ZignaturesModel::data(const QModelIndex &index, int role) const return QVariant::fromValue(zignature); case Qt::ToolTipRole: { - QString tmp = QString("Graph:\n\n Cyclomatic complexity: " + RSizeString(zignature.cc) - + "\n Nodes / basicblocks: " + RSizeString(zignature.nbbs) - + "\n Edges: " + RSizeString(zignature.edges) - + "\n Ebbs: " + RSizeString(zignature.ebbs) + "\n\nRefs:\n"); + QString tmp = QString("Graph:\n\n Cyclomatic complexity: " + RzSizeString(zignature.cc) + + "\n Nodes / basicblocks: " + RzSizeString(zignature.nbbs) + + "\n Edges: " + RzSizeString(zignature.edges) + + "\n Ebbs: " + RzSizeString(zignature.ebbs) + "\n\nRefs:\n"); for (const QString &ref : zignature.refs) { tmp.append("\n " + ref); } From 8fd35f21090e562c6589c4c6ed9e83e7faf2317a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Tue, 14 Sep 2021 18:59:04 +0200 Subject: [PATCH 018/240] Replace eco Command with API (Fix #2751) (#2759) --- rizin | 2 +- src/common/ColorThemeWorker.cpp | 5 +++-- src/common/Configuration.cpp | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/rizin b/rizin index 004edb89..709a1814 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 004edb899fe0a841ce4226c6b57c198c0baff402 +Subproject commit 709a1814d8302fd3fd905fd60d4a3ee4510ad7c3 diff --git a/src/common/ColorThemeWorker.cpp b/src/common/ColorThemeWorker.cpp index 4b7052e1..34851920 100644 --- a/src/common/ColorThemeWorker.cpp +++ b/src/common/ColorThemeWorker.cpp @@ -131,9 +131,10 @@ QJsonDocument ColorThemeWorker::getTheme(const QString &themeName) const QString curr = Config()->getColorTheme(); if (themeName != curr) { - Core()->cmdRaw(QString("eco %1").arg(themeName)); + RzCoreLocked core(Core()); + rz_core_load_theme(core, themeName.toUtf8().constData()); theme = Core()->cmdj("ecj").object().toVariantMap(); - Core()->cmdRaw(QString("eco %1").arg(curr)); + rz_core_load_theme(core, curr.toUtf8().constData()); } else { theme = Core()->cmdj("ecj").object().toVariantMap(); } diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 929b9173..133b0610 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -522,7 +522,7 @@ void Configuration::setColorTheme(const QString &theme) Core()->cmdRaw("ecd"); s.setValue("theme", "default"); } else { - Core()->cmdRaw(QStringLiteral("eco %1").arg(theme)); + rz_core_load_theme(Core()->core(), theme.toUtf8().constData()); s.setValue("theme", theme); } From 57f34bfb98719f3990466d96f18574675372f612 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 15 Sep 2021 05:40:01 +0800 Subject: [PATCH 019/240] Use open API instead of commands (#2757) --- src/common/AnalTask.cpp | 10 ++++++---- src/core/Cutter.cpp | 40 +++++++++++++++++++--------------------- src/core/Cutter.h | 1 - 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/common/AnalTask.cpp b/src/common/AnalTask.cpp index 81cfecd7..7a9fda27 100644 --- a/src/common/AnalTask.cpp +++ b/src/common/AnalTask.cpp @@ -19,8 +19,9 @@ void AnalTask::interrupt() QString AnalTask::getTitle() { // If no file is loaded we consider it's Initial Analysis - QJsonArray openedFiles = Core()->getOpenedFiles(); - if (!openedFiles.size()) { + RzCoreLocked core(Core()); + RzList *descs = rz_id_storage_list(core->io->files); + if (rz_list_empty(descs)) { return tr("Initial Analysis"); } return tr("Analyzing Program"); @@ -38,8 +39,9 @@ void AnalTask::runTask() Core()->setConfig("bin.demangle", options.demangle); // Do not reload the file if already loaded - QJsonArray openedFiles = Core()->getOpenedFiles(); - if (!openedFiles.size() && options.filename.length()) { + RzCoreLocked core(Core()); + RzList *descs = rz_id_storage_list(core->io->files); + if (rz_list_empty(descs) && options.filename.length()) { log(tr("Loading the file...")); openFailed = false; bool fileLoaded = diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 4f21288e..8791250c 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -386,11 +386,12 @@ bool CutterCore::isRedirectableDebugee() } // We are only able to redirect locally debugged unix processes - QJsonArray openFilesArray = cmdj("oj").array(); - ; - for (QJsonValue value : openFilesArray) { - QJsonObject openFile = value.toObject(); - QString URI = openFile["uri"].toString(); + RzCoreLocked core(Core()); + RzList *descs = rz_id_storage_list(core->io->files); + RzListIter *it; + RzIODesc *desc; + CutterRzListForeach(descs, it, RzIODesc, desc) { + QString URI = QString(desc->uri); if (URI.contains("ptrace") | URI.contains("mach")) { return true; } @@ -1913,10 +1914,12 @@ void CutterCore::attachRemote(const QString &uri) debugTask.clear(); // Check if we actually connected bool connected = false; - QJsonArray openFilesArray = getOpenedFiles(); - for (QJsonValue value : openFilesArray) { - QJsonObject openFile = value.toObject(); - QString fileUri = openFile["uri"].toString(); + RzCoreLocked core(Core()); + RzList *descs = rz_id_storage_list(core->io->files); + RzListIter *it; + RzIODesc *desc; + CutterRzListForeach(descs, it, RzIODesc, desc) { + QString fileUri = QString(desc->uri); if (!fileUri.compare(uri)) { connected = true; } @@ -2023,13 +2026,14 @@ void CutterCore::stopDebug() } else { QString ptraceFiles = ""; // close ptrace file descriptors left open - QJsonArray openFilesArray = cmdj("oj").array(); - ; - for (QJsonValue value : openFilesArray) { - QJsonObject openFile = value.toObject(); - QString URI = openFile["uri"].toString(); + RzCoreLocked core(Core()); + RzList *descs = rz_id_storage_list(core->io->files); + RzListIter *it; + RzIODesc *desc; + CutterRzListForeach(descs, it, RzIODesc, desc) { + QString URI = QString(desc->uri); if (URI.contains("ptrace")) { - ptraceFiles += "o-" + QString::number(openFile["fd"].toInt()) + ";"; + ptraceFiles += "o-" + QString::number(desc->fd) + ";"; } } // Use cmd because cmdRaw would not work with command concatenation @@ -4025,12 +4029,6 @@ QString CutterCore::getVersionInformation() return versionInfo; } -QJsonArray CutterCore::getOpenedFiles() -{ - QJsonDocument files = cmdj("oj"); - return files.array(); -} - QList CutterCore::getColorThemes() { QList r; diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 375943d1..cd382444 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -278,7 +278,6 @@ public: bool tryFile(QString path, bool rw); bool mapFile(QString path, RVA mapaddr); void loadScript(const QString &scriptname); - QJsonArray getOpenedFiles(); /* Seek functions */ void seek(QString thing); From 5595193b70b42a67c5e56e6d79a8cea55ecd1192 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Thu, 16 Sep 2021 02:48:02 +0800 Subject: [PATCH 020/240] Minor renames of analysis-related things (#2761) --- src/CMakeLists.txt | 10 +-- src/CutterApplication.cpp | 26 +++---- src/CutterApplication.h | 2 +- src/common/{AnalTask.cpp => AnalysisTask.cpp} | 16 ++--- src/common/{AnalTask.h => AnalysisTask.h} | 6 +- src/common/InitialOptions.h | 2 +- src/core/Cutter.cpp | 52 +++++++------- src/core/Cutter.h | 16 ++--- src/core/CutterDescriptions.h | 12 ++-- src/core/MainWindow.cpp | 16 ++--- src/dialogs/EditMethodDialog.cpp | 22 +++--- src/dialogs/EditMethodDialog.h | 6 +- src/dialogs/InitialOptionsDialog.cpp | 72 +++++++++---------- src/dialogs/InitialOptionsDialog.h | 6 +- src/dialogs/InitialOptionsDialog.ui | 6 +- ...nsWidget.cpp => AnalysisOptionsWidget.cpp} | 54 +++++++------- ...ptionsWidget.h => AnalysisOptionsWidget.h} | 20 +++--- ...ionsWidget.ui => AnalysisOptionsWidget.ui} | 6 +- src/dialogs/preferences/PreferencesDialog.cpp | 4 +- src/widgets/ClassesWidget.cpp | 72 +++++++++---------- src/widgets/ClassesWidget.h | 6 +- 21 files changed, 216 insertions(+), 216 deletions(-) rename src/common/{AnalTask.cpp => AnalysisTask.cpp} (90%) rename src/common/{AnalTask.h => AnalysisTask.h} (87%) rename src/dialogs/preferences/{AnalOptionsWidget.cpp => AnalysisOptionsWidget.cpp} (59%) rename src/dialogs/preferences/{AnalOptionsWidget.h => AnalysisOptionsWidget.h} (77%) rename src/dialogs/preferences/{AnalOptionsWidget.ui => AnalysisOptionsWidget.ui} (98%) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 97aefbfb..a8cead25 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,7 +24,7 @@ set(SOURCES common/DirectionalComboBox.cpp dialogs/preferences/AsmOptionsWidget.cpp dialogs/NewFileDialog.cpp - common/AnalTask.cpp + common/AnalysisTask.cpp widgets/CommentsWidget.cpp widgets/ConsoleWidget.cpp widgets/Dashboard.cpp @@ -139,7 +139,7 @@ set(SOURCES widgets/RizinGraphWidget.cpp widgets/CallGraph.cpp widgets/AddressableDockWidget.cpp - dialogs/preferences/AnalOptionsWidget.cpp + dialogs/preferences/AnalysisOptionsWidget.cpp common/DecompilerHighlighter.cpp dialogs/GlibcHeapInfoDialog.cpp widgets/HeapDockWidget.cpp @@ -173,7 +173,7 @@ set(HEADER_FILES common/DirectionalComboBox.h dialogs/InitialOptionsDialog.h dialogs/NewFileDialog.h - common/AnalTask.h + common/AnalysisTask.h widgets/CommentsWidget.h widgets/ConsoleWidget.h widgets/Dashboard.h @@ -298,7 +298,7 @@ set(HEADER_FILES widgets/RizinGraphWidget.h widgets/CallGraph.h widgets/AddressableDockWidget.h - dialogs/preferences/AnalOptionsWidget.h + dialogs/preferences/AnalysisOptionsWidget.h common/DecompilerHighlighter.h dialogs/GlibcHeapInfoDialog.h widgets/HeapDockWidget.h @@ -371,7 +371,7 @@ set(UI_FILES widgets/ListDockWidget.ui dialogs/LayoutManager.ui widgets/RizinGraphWidget.ui - dialogs/preferences/AnalOptionsWidget.ui + dialogs/preferences/AnalysisOptionsWidget.ui dialogs/GlibcHeapInfoDialog.ui widgets/HeapDockWidget.ui widgets/GlibcHeapWidget.ui diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index 60937679..d0134c91 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -149,7 +149,7 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc } mainWindow->displayNewFileDialog(); } else { // filename specified as positional argument - bool askOptions = (clOptions.analLevel != AutomaticAnalysisLevel::Ask) + bool askOptions = (clOptions.analysisLevel != AutomaticAnalysisLevel::Ask) || !clOptions.fileOpenOptions.projectFile.isEmpty(); mainWindow->openNewFile(clOptions.fileOpenOptions, askOptions); } @@ -378,30 +378,30 @@ bool CutterApplication::parseCommandLineOptions() opts.args = cmd_parser.positionalArguments(); if (cmd_parser.isSet(analOption)) { - bool analLevelSpecified = false; - int analLevel = cmd_parser.value(analOption).toInt(&analLevelSpecified); + bool analysisLevelSpecified = false; + int analysisLevel = cmd_parser.value(analOption).toInt(&analysisLevelSpecified); - if (!analLevelSpecified || analLevel < 0 || analLevel > 2) { + if (!analysisLevelSpecified || analysisLevel < 0 || analysisLevel > 2) { fprintf(stderr, "%s\n", QObject::tr("Invalid Analysis Level. May be a value between 0 and 2.") .toLocal8Bit() .constData()); return false; } - switch (analLevel) { + switch (analysisLevel) { case 0: - opts.analLevel = AutomaticAnalysisLevel::None; + opts.analysisLevel = AutomaticAnalysisLevel::None; break; case 1: - opts.analLevel = AutomaticAnalysisLevel::AAA; + opts.analysisLevel = AutomaticAnalysisLevel::AAA; break; case 2: - opts.analLevel = AutomaticAnalysisLevel::AAAA; + opts.analysisLevel = AutomaticAnalysisLevel::AAAA; break; } } - if (opts.args.empty() && opts.analLevel != AutomaticAnalysisLevel::Ask) { + if (opts.args.empty() && opts.analysisLevel != AutomaticAnalysisLevel::Ask) { fprintf(stderr, "%s\n", QObject::tr("Filename must be specified to start analysis automatically.") .toLocal8Bit() @@ -420,17 +420,17 @@ bool CutterApplication::parseCommandLineOptions() options.binLoadAddr = baddr; } } - switch (opts.analLevel) { + switch (opts.analysisLevel) { case AutomaticAnalysisLevel::Ask: break; case AutomaticAnalysisLevel::None: - opts.fileOpenOptions.analCmd = {}; + opts.fileOpenOptions.analysisCmd = {}; break; case AutomaticAnalysisLevel::AAA: - opts.fileOpenOptions.analCmd = { { "aaa", "Auto analysis" } }; + opts.fileOpenOptions.analysisCmd = { { "aaa", "Auto analysis" } }; break; case AutomaticAnalysisLevel::AAAA: - opts.fileOpenOptions.analCmd = { { "aaaa", "Auto analysis (experimental)" } }; + opts.fileOpenOptions.analysisCmd = { { "aaaa", "Auto analysis (experimental)" } }; break; } opts.fileOpenOptions.script = cmd_parser.value(scriptOption); diff --git a/src/CutterApplication.h b/src/CutterApplication.h index cf2fd4d0..f8dc01e3 100644 --- a/src/CutterApplication.h +++ b/src/CutterApplication.h @@ -13,7 +13,7 @@ enum class AutomaticAnalysisLevel { Ask, None, AAA, AAAA }; struct CutterCommandLineOptions { QStringList args; - AutomaticAnalysisLevel analLevel = AutomaticAnalysisLevel::Ask; + AutomaticAnalysisLevel analysisLevel = AutomaticAnalysisLevel::Ask; InitialOptions fileOpenOptions; QString pythonHome; bool outputRedirectionEnabled = true; diff --git a/src/common/AnalTask.cpp b/src/common/AnalysisTask.cpp similarity index 90% rename from src/common/AnalTask.cpp rename to src/common/AnalysisTask.cpp index 7a9fda27..5752a470 100644 --- a/src/common/AnalTask.cpp +++ b/src/common/AnalysisTask.cpp @@ -1,22 +1,22 @@ #include "core/Cutter.h" -#include "common/AnalTask.h" +#include "common/AnalysisTask.h" #include "core/MainWindow.h" #include "dialogs/InitialOptionsDialog.h" #include #include #include -AnalTask::AnalTask() : AsyncTask() {} +AnalysisTask::AnalysisTask() : AsyncTask() {} -AnalTask::~AnalTask() {} +AnalysisTask::~AnalysisTask() {} -void AnalTask::interrupt() +void AnalysisTask::interrupt() { AsyncTask::interrupt(); rz_cons_singleton()->context->breaked = true; } -QString AnalTask::getTitle() +QString AnalysisTask::getTitle() { // If no file is loaded we consider it's Initial Analysis RzCoreLocked core(Core()); @@ -27,7 +27,7 @@ QString AnalTask::getTitle() return tr("Analyzing Program"); } -void AnalTask::runTask() +void AnalysisTask::runTask() { int perms = RZ_PERM_RX; if (options.writeEnabled) { @@ -96,9 +96,9 @@ void AnalTask::runTask() return; } - if (!options.analCmd.empty()) { + if (!options.analysisCmd.empty()) { log(tr("Executing analysis...")); - for (const CommandDescription &cmd : options.analCmd) { + for (const CommandDescription &cmd : options.analysisCmd) { if (isInterrupted()) { return; } diff --git a/src/common/AnalTask.h b/src/common/AnalysisTask.h similarity index 87% rename from src/common/AnalTask.h rename to src/common/AnalysisTask.h index 305d8fc2..6b992fd9 100644 --- a/src/common/AnalTask.h +++ b/src/common/AnalysisTask.h @@ -9,13 +9,13 @@ class CutterCore; class MainWindow; class InitialOptionsDialog; -class AnalTask : public AsyncTask +class AnalysisTask : public AsyncTask { Q_OBJECT public: - explicit AnalTask(); - ~AnalTask(); + explicit AnalysisTask(); + ~AnalysisTask(); QString getTitle() override; diff --git a/src/common/InitialOptions.h b/src/common/InitialOptions.h index 9e6413b0..36ede2d4 100644 --- a/src/common/InitialOptions.h +++ b/src/common/InitialOptions.h @@ -40,7 +40,7 @@ struct InitialOptions QString pdbFile; QString script; - QList analCmd = { { "aaa", "Auto analysis" } }; + QList analysisCmd = { { "aaa", "Auto analysis" } }; QString shellcode; }; diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 8791250c..439c4db3 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -2706,7 +2706,7 @@ QStringList CutterCore::getAsmPluginNames() return ret; } -QStringList CutterCore::getAnalPluginNames() +QStringList CutterCore::getAnalysisPluginNames() { CORE_LOCK(); RzListIter *it; @@ -3305,7 +3305,7 @@ QList CutterCore::getAllClassesFromFlags() return ret; } -QList CutterCore::getAllAnalClasses(bool sorted) +QList CutterCore::getAllAnalysisClasses(bool sorted) { CORE_LOCK(); QList ret; @@ -3327,10 +3327,10 @@ QList CutterCore::getAllAnalClasses(bool sorted) return ret; } -QList CutterCore::getAnalClassMethods(const QString &cls) +QList CutterCore::getAnalysisClassMethods(const QString &cls) { CORE_LOCK(); - QList ret; + QList ret; RzVector *meths = rz_analysis_class_method_get_all(core->analysis, cls.toUtf8().constData()); if (!meths) { @@ -3341,7 +3341,7 @@ QList CutterCore::getAnalClassMethods(const QString &cls) RzAnalysisMethod *meth; CutterRzVectorForeach(meths, meth, RzAnalysisMethod) { - AnalMethodDescription desc; + AnalysisMethodDescription desc; desc.name = QString::fromUtf8(meth->name); desc.addr = meth->addr; desc.vtableOffset = meth->vtable_offset; @@ -3352,10 +3352,10 @@ QList CutterCore::getAnalClassMethods(const QString &cls) return ret; } -QList CutterCore::getAnalClassBaseClasses(const QString &cls) +QList CutterCore::getAnalysisClassBaseClasses(const QString &cls) { CORE_LOCK(); - QList ret; + QList ret; RzVector *bases = rz_analysis_class_base_get_all(core->analysis, cls.toUtf8().constData()); if (!bases) { @@ -3366,7 +3366,7 @@ QList CutterCore::getAnalClassBaseClasses(const QStrin RzAnalysisBaseClass *base; CutterRzVectorForeach(bases, base, RzAnalysisBaseClass) { - AnalBaseClassDescription desc; + AnalysisBaseClassDescription desc; desc.id = QString::fromUtf8(base->id); desc.offset = base->offset; desc.className = QString::fromUtf8(base->class_name); @@ -3377,10 +3377,10 @@ QList CutterCore::getAnalClassBaseClasses(const QStrin return ret; } -QList CutterCore::getAnalClassVTables(const QString &cls) +QList CutterCore::getAnalysisClassVTables(const QString &cls) { CORE_LOCK(); - QList acVtables; + QList acVtables; RzVector *vtables = rz_analysis_class_vtable_get_all(core->analysis, cls.toUtf8().constData()); if (!vtables) { @@ -3391,7 +3391,7 @@ QList CutterCore::getAnalClassVTables(const QString &cls) RzAnalysisVTable *vtable; CutterRzVectorForeach(vtables, vtable, RzAnalysisVTable) { - AnalVTableDescription desc; + AnalysisVTableDescription desc; desc.id = QString::fromUtf8(vtable->id); desc.offset = vtable->offset; desc.addr = vtable->addr; @@ -3421,34 +3421,34 @@ void CutterCore::deleteClass(const QString &cls) rz_analysis_class_delete(core->analysis, cls.toUtf8().constData()); } -bool CutterCore::getAnalMethod(const QString &cls, const QString &meth, AnalMethodDescription *desc) +bool CutterCore::getAnalysisMethod(const QString &cls, const QString &meth, AnalysisMethodDescription *desc) { CORE_LOCK(); - RzAnalysisMethod analMeth; + RzAnalysisMethod analysisMeth; if (rz_analysis_class_method_get(core->analysis, cls.toUtf8().constData(), - meth.toUtf8().constData(), &analMeth) + meth.toUtf8().constData(), &analysisMeth) != RZ_ANALYSIS_CLASS_ERR_SUCCESS) { return false; } - desc->name = QString::fromUtf8(analMeth.name); - desc->addr = analMeth.addr; - desc->vtableOffset = analMeth.vtable_offset; - rz_analysis_class_method_fini(&analMeth); + desc->name = QString::fromUtf8(analysisMeth.name); + desc->addr = analysisMeth.addr; + desc->vtableOffset = analysisMeth.vtable_offset; + rz_analysis_class_method_fini(&analysisMeth); return true; } -void CutterCore::setAnalMethod(const QString &className, const AnalMethodDescription &meth) +void CutterCore::setAnalysisMethod(const QString &className, const AnalysisMethodDescription &meth) { CORE_LOCK(); - RzAnalysisMethod analMeth; - analMeth.name = strdup(meth.name.toUtf8().constData()); - analMeth.addr = meth.addr; - analMeth.vtable_offset = meth.vtableOffset; - rz_analysis_class_method_set(core->analysis, className.toUtf8().constData(), &analMeth); - rz_analysis_class_method_fini(&analMeth); + RzAnalysisMethod analysisMeth; + analysisMeth.name = strdup(meth.name.toUtf8().constData()); + analysisMeth.addr = meth.addr; + analysisMeth.vtable_offset = meth.vtableOffset; + rz_analysis_class_method_set(core->analysis, className.toUtf8().constData(), &analysisMeth); + rz_analysis_class_method_fini(&analysisMeth); } -void CutterCore::renameAnalMethod(const QString &className, const QString &oldMethodName, +void CutterCore::renameAnalysisMethod(const QString &className, const QString &oldMethodName, const QString &newMethodName) { CORE_LOCK(); diff --git a/src/core/Cutter.h b/src/core/Cutter.h index cd382444..54a7bb55 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -260,17 +260,17 @@ public: void applyStructureOffset(const QString &structureOffset, RVA offset = RVA_INVALID); /* Classes */ - QList getAllAnalClasses(bool sorted); - QList getAnalClassMethods(const QString &cls); - QList getAnalClassBaseClasses(const QString &cls); - QList getAnalClassVTables(const QString &cls); + QList getAllAnalysisClasses(bool sorted); + QList getAnalysisClassMethods(const QString &cls); + QList getAnalysisClassBaseClasses(const QString &cls); + QList getAnalysisClassVTables(const QString &cls); void createNewClass(const QString &cls); void renameClass(const QString &oldName, const QString &newName); void deleteClass(const QString &cls); - bool getAnalMethod(const QString &cls, const QString &meth, AnalMethodDescription *desc); - void renameAnalMethod(const QString &className, const QString &oldMethodName, + bool getAnalysisMethod(const QString &cls, const QString &meth, AnalysisMethodDescription *desc); + void renameAnalysisMethod(const QString &className, const QString &oldMethodName, const QString &newMethodName); - void setAnalMethod(const QString &cls, const AnalMethodDescription &meth); + void setAnalysisMethod(const QString &cls, const AnalysisMethodDescription &meth); /* File related methods */ bool loadFile(QString path, ut64 baddr = 0LL, ut64 mapaddr = 0LL, int perms = RZ_PERM_R, @@ -531,7 +531,7 @@ public: /* Plugins */ QStringList getAsmPluginNames(); - QStringList getAnalPluginNames(); + QStringList getAnalysisPluginNames(); /* Widgets */ QList getRBinPluginDescriptions(const QString &type = QString()); diff --git a/src/core/CutterDescriptions.h b/src/core/CutterDescriptions.h index 12170f92..aa786185 100644 --- a/src/core/CutterDescriptions.h +++ b/src/core/CutterDescriptions.h @@ -244,21 +244,21 @@ struct BinClassDescription QList fields; }; -struct AnalMethodDescription +struct AnalysisMethodDescription { QString name; RVA addr; st64 vtableOffset; }; -struct AnalBaseClassDescription +struct AnalysisBaseClassDescription { QString id; RVA offset; QString className; }; -struct AnalVTableDescription +struct AnalysisVTableDescription { QString id; ut64 offset; @@ -404,9 +404,9 @@ Q_DECLARE_METATYPE(BinClassDescription) Q_DECLARE_METATYPE(const BinClassDescription *) Q_DECLARE_METATYPE(const BinClassMethodDescription *) Q_DECLARE_METATYPE(const BinClassFieldDescription *) -Q_DECLARE_METATYPE(AnalBaseClassDescription) -Q_DECLARE_METATYPE(AnalMethodDescription) -Q_DECLARE_METATYPE(AnalVTableDescription) +Q_DECLARE_METATYPE(AnalysisBaseClassDescription) +Q_DECLARE_METATYPE(AnalysisMethodDescription) +Q_DECLARE_METATYPE(AnalysisVTableDescription) Q_DECLARE_METATYPE(ResourcesDescription) Q_DECLARE_METATYPE(VTableDescription) Q_DECLARE_METATYPE(TypeDescription) diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index 9677317a..e7cbe173 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -2,7 +2,7 @@ #include "ui_MainWindow.h" // Common Headers -#include "common/AnalTask.h" +#include "common/AnalysisTask.h" #include "common/BugReporting.h" #include "common/Highlighter.h" #include "common/Helpers.h" @@ -1652,19 +1652,19 @@ void MainWindow::on_actionRefresh_Panels_triggered() */ void MainWindow::on_actionAnalyze_triggered() { - auto *analTask = new AnalTask(); + auto *analysisTask = new AnalysisTask(); InitialOptions options; - options.analCmd = { { "aaa", "Auto analysis" } }; - analTask->setOptions(options); - AsyncTask::Ptr analTaskPtr(analTask); + options.analysisCmd = { { "aaa", "Auto analysis" } }; + analysisTask->setOptions(options); + AsyncTask::Ptr analysisTaskPtr(analysisTask); - auto *taskDialog = new AsyncTaskDialog(analTaskPtr); + auto *taskDialog = new AsyncTaskDialog(analysisTaskPtr); taskDialog->setInterruptOnClose(true); taskDialog->setAttribute(Qt::WA_DeleteOnClose); taskDialog->show(); - connect(analTask, &AnalTask::finished, this, &MainWindow::refreshAll); + connect(analysisTask, &AnalysisTask::finished, this, &MainWindow::refreshAll); - Core()->getAsyncTaskManager()->start(analTaskPtr); + Core()->getAsyncTaskManager()->start(analysisTaskPtr); } void MainWindow::on_actionImportPDB_triggered() diff --git a/src/dialogs/EditMethodDialog.cpp b/src/dialogs/EditMethodDialog.cpp index fef6251e..28914f80 100644 --- a/src/dialogs/EditMethodDialog.cpp +++ b/src/dialogs/EditMethodDialog.cpp @@ -15,7 +15,7 @@ EditMethodDialog::EditMethodDialog(bool classFixed, QWidget *parent) } else { classComboBox = new QComboBox(this); ui->formLayout->setItem(0, QFormLayout::FieldRole, new QWidgetItem(classComboBox)); - for (auto &cls : Core()->getAllAnalClasses(true)) { + for (auto &cls : Core()->getAllAnalysisClasses(true)) { classComboBox->addItem(cls, cls); } } @@ -86,7 +86,7 @@ void EditMethodDialog::setClass(const QString &className) validateInput(); } -void EditMethodDialog::setMethod(const AnalMethodDescription &desc) +void EditMethodDialog::setMethod(const AnalysisMethodDescription &desc) { ui->nameEdit->setText(desc.name); ui->addressEdit->setText(desc.addr != RVA_INVALID ? RzAddressString(desc.addr) : nullptr); @@ -116,9 +116,9 @@ QString EditMethodDialog::getClass() const } } -AnalMethodDescription EditMethodDialog::getMethod() const +AnalysisMethodDescription EditMethodDialog::getMethod() const { - AnalMethodDescription ret; + AnalysisMethodDescription ret; ret.name = ui->nameEdit->text(); ret.addr = Core()->num(ui->addressEdit->text()); if (!ui->virtualCheckBox->isChecked()) { @@ -130,7 +130,7 @@ AnalMethodDescription EditMethodDialog::getMethod() const } bool EditMethodDialog::showDialog(const QString &title, bool classFixed, QString *className, - AnalMethodDescription *desc, QWidget *parent) + AnalysisMethodDescription *desc, QWidget *parent) { EditMethodDialog dialog(classFixed, parent); dialog.setWindowTitle(title); @@ -144,7 +144,7 @@ bool EditMethodDialog::showDialog(const QString &title, bool classFixed, QString void EditMethodDialog::newMethod(QString className, const QString &meth, QWidget *parent) { - AnalMethodDescription desc; + AnalysisMethodDescription desc; desc.name = meth; desc.vtableOffset = -1; desc.addr = Core()->getOffset(); @@ -153,13 +153,13 @@ void EditMethodDialog::newMethod(QString className, const QString &meth, QWidget return; } - Core()->setAnalMethod(className, desc); + Core()->setAnalysisMethod(className, desc); } void EditMethodDialog::editMethod(const QString &className, const QString &meth, QWidget *parent) { - AnalMethodDescription desc; - if (!Core()->getAnalMethod(className, meth, &desc)) { + AnalysisMethodDescription desc; + if (!Core()->getAnalysisMethod(className, meth, &desc)) { return; } @@ -168,7 +168,7 @@ void EditMethodDialog::editMethod(const QString &className, const QString &meth, return; } if (desc.name != meth) { - Core()->renameAnalMethod(className, meth, desc.name); + Core()->renameAnalysisMethod(className, meth, desc.name); } - Core()->setAnalMethod(className, desc); + Core()->setAnalysisMethod(className, desc); } diff --git a/src/dialogs/EditMethodDialog.h b/src/dialogs/EditMethodDialog.h index a7a59bcc..df414977 100644 --- a/src/dialogs/EditMethodDialog.h +++ b/src/dialogs/EditMethodDialog.h @@ -24,10 +24,10 @@ public: ~EditMethodDialog(); void setClass(const QString &className); - void setMethod(const AnalMethodDescription &desc); + void setMethod(const AnalysisMethodDescription &desc); QString getClass() const; - AnalMethodDescription getMethod() const; + AnalysisMethodDescription getMethod() const; /** * @brief Helper function to display the dialog @@ -39,7 +39,7 @@ public: * @return whether the dialog was accepted by the user */ static bool showDialog(const QString &title, bool classFixed, QString *className, - AnalMethodDescription *desc, QWidget *parent = nullptr); + AnalysisMethodDescription *desc, QWidget *parent = nullptr); /** * @brief Show the dialog to add a new method a given class diff --git a/src/dialogs/InitialOptionsDialog.cpp b/src/dialogs/InitialOptionsDialog.cpp index be171879..54622656 100644 --- a/src/dialogs/InitialOptionsDialog.cpp +++ b/src/dialogs/InitialOptionsDialog.cpp @@ -13,7 +13,7 @@ #include #include "core/Cutter.h" -#include "common/AnalTask.h" +#include "common/AnalysisTask.h" InitialOptionsDialog::InitialOptionsDialog(MainWindow *main) : QDialog(nullptr), // parent must not be main @@ -83,7 +83,7 @@ InitialOptionsDialog::InitialOptionsDialog(MainWindow *main) } ui->hideFrame->setVisible(false); - ui->analoptionsFrame->setVisible(false); + ui->analysisoptionsFrame->setVisible(false); ui->advancedAnlysisLine->setVisible(false); updatePDBLayout(); @@ -132,7 +132,7 @@ void InitialOptionsDialog::updateCPUComboBox() QList InitialOptionsDialog::getAnalysisCommands(const InitialOptions &options) { QList commands; - for (auto &commandDesc : options.analCmd) { + for (auto &commandDesc : options.analysisCmd) { commands << commandDesc.command; } return commands; @@ -140,14 +140,14 @@ QList InitialOptionsDialog::getAnalysisCommands(const InitialOptions &o void InitialOptionsDialog::loadOptions(const InitialOptions &options) { - if (options.analCmd.isEmpty()) { - analLevel = 0; - } else if (options.analCmd.first().command == "aaa") { - analLevel = 1; - } else if (options.analCmd.first().command == "aaaa") { - analLevel = 2; + if (options.analysisCmd.isEmpty()) { + analysisLevel = 0; + } else if (options.analysisCmd.first().command == "aaa") { + analysisLevel = 1; + } else if (options.analysisCmd.first().command == "aaaa") { + analysisLevel = 2; } else { - analLevel = 3; + analysisLevel = 3; AnalysisCommands item; QList commands = getAnalysisCommands(options); foreach (item, analysisCommands) { @@ -159,13 +159,13 @@ void InitialOptionsDialog::loadOptions(const InitialOptions &options) if (!options.script.isEmpty()) { ui->scriptCheckBox->setChecked(true); ui->scriptLineEdit->setText(options.script); - analLevel = 0; + analysisLevel = 0; } else { ui->scriptCheckBox->setChecked(false); ui->scriptLineEdit->setText(""); } - ui->analSlider->setValue(analLevel); + ui->analysisSlider->setValue(analysisLevel); shellcode = options.shellcode; @@ -235,7 +235,7 @@ QString InitialOptionsDialog::getSelectedOS() const QList InitialOptionsDialog::getSelectedAdvancedAnalCmds() const { QList advanced = QList(); - if (ui->analSlider->value() == 3) { + if (ui->analysisSlider->value() == 3) { AnalysisCommands item; foreach (item, analysisCommands) { if (item.checkbox->isChecked()) { @@ -284,42 +284,42 @@ void InitialOptionsDialog::setupAndStartAnalysis(/*int level, QList adv options.endian = getSelectedEndianness(); - int level = ui->analSlider->value(); + int level = ui->analysisSlider->value(); switch (level) { case 1: - options.analCmd = { { "aaa", "Auto analysis" } }; + options.analysisCmd = { { "aaa", "Auto analysis" } }; break; case 2: - options.analCmd = { { "aaaa", "Auto analysis (experimental)" } }; + options.analysisCmd = { { "aaaa", "Auto analysis (experimental)" } }; break; case 3: - options.analCmd = getSelectedAdvancedAnalCmds(); + options.analysisCmd = getSelectedAdvancedAnalCmds(); break; default: - options.analCmd = {}; + options.analysisCmd = {}; break; } - AnalTask *analTask = new AnalTask(); - analTask->setOptions(options); + AnalysisTask *analysisTask = new AnalysisTask(); + analysisTask->setOptions(options); MainWindow *main = this->main; - connect(analTask, &AnalTask::openFileFailed, main, &MainWindow::openNewFileFailed); - connect(analTask, &AsyncTask::finished, main, [analTask, main]() { - if (analTask->getOpenFileFailed()) { + connect(analysisTask, &AnalysisTask::openFileFailed, main, &MainWindow::openNewFileFailed); + connect(analysisTask, &AsyncTask::finished, main, [analysisTask, main]() { + if (analysisTask->getOpenFileFailed()) { return; } main->finalizeOpen(); }); - AsyncTask::Ptr analTaskPtr(analTask); + AsyncTask::Ptr analysisTaskPtr(analysisTask); - AsyncTaskDialog *taskDialog = new AsyncTaskDialog(analTaskPtr); + AsyncTaskDialog *taskDialog = new AsyncTaskDialog(analysisTaskPtr); taskDialog->setInterruptOnClose(true); taskDialog->setAttribute(Qt::WA_DeleteOnClose); taskDialog->show(); - Core()->getAsyncTaskManager()->start(analTaskPtr); + Core()->getAsyncTaskManager()->start(analysisTaskPtr); done(0); } @@ -352,20 +352,20 @@ QString InitialOptionsDialog::analysisDescription(int level) } } -void InitialOptionsDialog::on_analSlider_valueChanged(int value) +void InitialOptionsDialog::on_analysisSlider_valueChanged(int value) { ui->analDescription->setText(tr("Level") + QString(": %1").arg(analysisDescription(value))); if (value == 0) { - ui->analCheckBox->setChecked(false); - ui->analCheckBox->setText(tr("Analysis: Disabled")); + ui->analysisCheckBox->setChecked(false); + ui->analysisCheckBox->setText(tr("Analysis: Disabled")); } else { - ui->analCheckBox->setChecked(true); - ui->analCheckBox->setText(tr("Analysis: Enabled")); + ui->analysisCheckBox->setChecked(true); + ui->analysisCheckBox->setText(tr("Analysis: Enabled")); if (value == 3) { - ui->analoptionsFrame->setVisible(true); + ui->analysisoptionsFrame->setVisible(true); ui->advancedAnlysisLine->setVisible(true); } else { - ui->analoptionsFrame->setVisible(false); + ui->analysisoptionsFrame->setVisible(false); ui->advancedAnlysisLine->setVisible(false); } } @@ -382,12 +382,12 @@ void InitialOptionsDialog::on_AdvOptButton_clicked() } } -void InitialOptionsDialog::on_analCheckBox_clicked(bool checked) +void InitialOptionsDialog::on_analysisCheckBox_clicked(bool checked) { if (!checked) { - analLevel = ui->analSlider->value(); + analysisLevel = ui->analysisSlider->value(); } - ui->analSlider->setValue(checked ? analLevel : 0); + ui->analysisSlider->setValue(checked ? analysisLevel : 0); } void InitialOptionsDialog::on_archComboBox_currentIndexChanged(int) diff --git a/src/dialogs/InitialOptionsDialog.h b/src/dialogs/InitialOptionsDialog.h index f8c24003..90de4394 100644 --- a/src/dialogs/InitialOptionsDialog.h +++ b/src/dialogs/InitialOptionsDialog.h @@ -24,9 +24,9 @@ public: private slots: void on_okButton_clicked(); - void on_analSlider_valueChanged(int value); + void on_analysisSlider_valueChanged(int value); void on_AdvOptButton_clicked(); - void on_analCheckBox_clicked(bool checked); + void on_analysisCheckBox_clicked(bool checked); void on_archComboBox_currentIndexChanged(int index); void on_pdbSelectButton_clicked(); void on_scriptSelectButton_clicked(); @@ -45,7 +45,7 @@ private: QString analysisDescription(int level); QString shellcode; - int analLevel; + int analysisLevel; QList asmPlugins; void updateCPUComboBox(); diff --git a/src/dialogs/InitialOptionsDialog.ui b/src/dialogs/InitialOptionsDialog.ui index ebb18ae0..3b8cc363 100644 --- a/src/dialogs/InitialOptionsDialog.ui +++ b/src/dialogs/InitialOptionsDialog.ui @@ -144,7 +144,7 @@ - + 0 @@ -181,7 +181,7 @@ - + 0 @@ -277,7 +277,7 @@ QLayout::SetMinimumSize - + true diff --git a/src/dialogs/preferences/AnalOptionsWidget.cpp b/src/dialogs/preferences/AnalysisOptionsWidget.cpp similarity index 59% rename from src/dialogs/preferences/AnalOptionsWidget.cpp rename to src/dialogs/preferences/AnalysisOptionsWidget.cpp index 83ed18b6..53d00f2f 100644 --- a/src/dialogs/preferences/AnalOptionsWidget.cpp +++ b/src/dialogs/preferences/AnalysisOptionsWidget.cpp @@ -1,5 +1,5 @@ -#include "AnalOptionsWidget.h" -#include "ui_AnalOptionsWidget.h" +#include "AnalysisOptionsWidget.h" +#include "ui_AnalysisOptionsWidget.h" #include "PreferencesDialog.h" @@ -8,7 +8,7 @@ #include "core/MainWindow.h" -static const QHash analBoundaries { +static const QHash analysisBoundaries { { "io.maps.x", "All executable maps" }, { "io.maps", "All maps" }, { "io.map", "Current map" }, @@ -17,8 +17,8 @@ static const QHash analBoundaries { { "bin.sections", "All mapped sections" }, }; -AnalOptionsWidget::AnalOptionsWidget(PreferencesDialog *dialog) - : QDialog(dialog), ui(new Ui::AnalOptionsWidget) +AnalysisOptionsWidget::AnalysisOptionsWidget(PreferencesDialog *dialog) + : QDialog(dialog), ui(new Ui::AnalysisOptionsWidget) { ui->setupUi(this); @@ -31,7 +31,7 @@ AnalOptionsWidget::AnalOptionsWidget(PreferencesDialog *dialog) { ui->verboseCheckBox, "analysis.verbose" } }; // Create list of options for the analysis.in selector - createAnalInOptionsList(); + createAnalysisInOptionsList(); // Connect each checkbox from "checkboxes" to the generic signal "checkboxEnabler" for (ConfigCheckbox &confCheckbox : checkboxes) { @@ -45,23 +45,23 @@ AnalOptionsWidget::AnalOptionsWidget(PreferencesDialog *dialog) auto *mainWindow = new MainWindow(this); connect(ui->analyzePushButton, &QPushButton::clicked, mainWindow, &MainWindow::on_actionAnalyze_triggered); - connect(ui->analInComboBox, &QComboBox::currentIndexChanged, this, - &AnalOptionsWidget::updateAnalIn); + connect(ui->analysisInComboBox, &QComboBox::currentIndexChanged, this, + &AnalysisOptionsWidget::updateAnalysisIn); connect(ui->ptrDepthSpinBox, &QSpinBox::valueChanged, this, - &AnalOptionsWidget::updateAnalPtrDepth); + &AnalysisOptionsWidget::updateAnalysisPtrDepth); connect(ui->preludeLineEdit, &QLineEdit::textChanged, this, - &AnalOptionsWidget::updateAnalPrelude); - updateAnalOptionsFromVars(); + &AnalysisOptionsWidget::updateAnalysisPrelude); + updateAnalysisOptionsFromVars(); } -AnalOptionsWidget::~AnalOptionsWidget() {} +AnalysisOptionsWidget::~AnalysisOptionsWidget() {} -void AnalOptionsWidget::checkboxEnabler(QCheckBox *checkBox, const QString &config) +void AnalysisOptionsWidget::checkboxEnabler(QCheckBox *checkBox, const QString &config) { Config()->setConfig(config, checkBox->isChecked()); } -void AnalOptionsWidget::updateAnalOptionsFromVars() +void AnalysisOptionsWidget::updateAnalysisOptionsFromVars() { for (ConfigCheckbox &confCheckbox : checkboxes) { qhelpers::setCheckedWithoutSignals(confCheckbox.checkBox, @@ -69,36 +69,36 @@ void AnalOptionsWidget::updateAnalOptionsFromVars() } // Update the rest of analysis options that are not checkboxes - ui->analInComboBox->setCurrentIndex( - ui->analInComboBox->findData(Core()->getConfig("analysis.in"))); + ui->analysisInComboBox->setCurrentIndex( + ui->analysisInComboBox->findData(Core()->getConfig("analysis.in"))); ui->ptrDepthSpinBox->setValue(Core()->getConfigi("analysis.ptrdepth")); ui->preludeLineEdit->setText(Core()->getConfig("analysis.prelude")); } -void AnalOptionsWidget::updateAnalIn(int index) +void AnalysisOptionsWidget::updateAnalysisIn(int index) { - Config()->setConfig("analysis.in", ui->analInComboBox->itemData(index).toString()); + Config()->setConfig("analysis.in", ui->analysisInComboBox->itemData(index).toString()); } -void AnalOptionsWidget::updateAnalPtrDepth(int value) +void AnalysisOptionsWidget::updateAnalysisPtrDepth(int value) { Config()->setConfig("analysis.ptrdepth", value); } -void AnalOptionsWidget::updateAnalPrelude(const QString &prelude) +void AnalysisOptionsWidget::updateAnalysisPrelude(const QString &prelude) { Config()->setConfig("analysis.prelude", prelude); } -void AnalOptionsWidget::createAnalInOptionsList() +void AnalysisOptionsWidget::createAnalysisInOptionsList() { QHash::const_iterator mapIter; - mapIter = analBoundaries.cbegin(); - ui->analInComboBox->blockSignals(true); - ui->analInComboBox->clear(); - for (; mapIter != analBoundaries.cend(); ++mapIter) { - ui->analInComboBox->addItem(mapIter.value(), mapIter.key()); + mapIter = analysisBoundaries.cbegin(); + ui->analysisInComboBox->blockSignals(true); + ui->analysisInComboBox->clear(); + for (; mapIter != analysisBoundaries.cend(); ++mapIter) { + ui->analysisInComboBox->addItem(mapIter.value(), mapIter.key()); } - ui->analInComboBox->blockSignals(false); + ui->analysisInComboBox->blockSignals(false); } diff --git a/src/dialogs/preferences/AnalOptionsWidget.h b/src/dialogs/preferences/AnalysisOptionsWidget.h similarity index 77% rename from src/dialogs/preferences/AnalOptionsWidget.h rename to src/dialogs/preferences/AnalysisOptionsWidget.h index fcb01ec6..bf50d0e7 100644 --- a/src/dialogs/preferences/AnalOptionsWidget.h +++ b/src/dialogs/preferences/AnalysisOptionsWidget.h @@ -9,19 +9,19 @@ class PreferencesDialog; namespace Ui { -class AnalOptionsWidget; +class AnalysisOptionsWidget; } -class AnalOptionsWidget : public QDialog +class AnalysisOptionsWidget : public QDialog { Q_OBJECT public: - explicit AnalOptionsWidget(PreferencesDialog *dialog); - ~AnalOptionsWidget(); + explicit AnalysisOptionsWidget(PreferencesDialog *dialog); + ~AnalysisOptionsWidget(); private: - std::unique_ptr ui; + std::unique_ptr ui; struct ConfigCheckbox { QCheckBox *checkBox; @@ -33,14 +33,14 @@ private: * @brief This function creates the list with the different options shown in the selector for * analysis.in */ - void createAnalInOptionsList(); + void createAnalysisInOptionsList(); private slots: /** * @brief A slot to display the options in the dialog according to the current analysis.* * configuration */ - void updateAnalOptionsFromVars(); + void updateAnalysisOptionsFromVars(); /** * @brief A generic slot to handle the simple cases where a checkbox is toggled @@ -54,20 +54,20 @@ private slots: * @brief A slot to update the value of analysis.in when a different option is selected * @param index - The index of the selected option for analysis.in */ - void updateAnalIn(int index); + void updateAnalysisIn(int index); /** * @brief A slot to update the value of analysis.ptrdepth when a new value is selected * @param value - The new value for analysis.ptrdepth */ - static void updateAnalPtrDepth(int value); + static void updateAnalysisPtrDepth(int value); /** * @brief slot to update the value of analysis.prelude when a new value is introduced in the * corresponding textbox * @param prelude - The new value for analysis.prelude */ - static void updateAnalPrelude(const QString &prelude); + static void updateAnalysisPrelude(const QString &prelude); }; #endif // ANALOPTIONSWIDGET_H diff --git a/src/dialogs/preferences/AnalOptionsWidget.ui b/src/dialogs/preferences/AnalysisOptionsWidget.ui similarity index 98% rename from src/dialogs/preferences/AnalOptionsWidget.ui rename to src/dialogs/preferences/AnalysisOptionsWidget.ui index 725506f4..9968558a 100644 --- a/src/dialogs/preferences/AnalOptionsWidget.ui +++ b/src/dialogs/preferences/AnalysisOptionsWidget.ui @@ -1,7 +1,7 @@ - AnalOptionsWidget - + AnalysisOptionsWidget + 0 @@ -163,7 +163,7 @@ - + diff --git a/src/dialogs/preferences/PreferencesDialog.cpp b/src/dialogs/preferences/PreferencesDialog.cpp index 968e08f1..26550901 100644 --- a/src/dialogs/preferences/PreferencesDialog.cpp +++ b/src/dialogs/preferences/PreferencesDialog.cpp @@ -7,7 +7,7 @@ #include "DebugOptionsWidget.h" #include "PluginsOptionsWidget.h" #include "InitializationFileEditor.h" -#include "AnalOptionsWidget.h" +#include "AnalysisOptionsWidget.h" #include "PreferenceCategory.h" @@ -36,7 +36,7 @@ PreferencesDialog::PreferencesDialog(QWidget *parent) { tr("Plugins"), new PluginsOptionsWidget(this), QIcon(":/img/icons/plugins.svg") }, { tr("Initialization Script"), new InitializationFileEditor(this), QIcon(":/img/icons/initialization.svg") }, - { tr("Analysis"), new AnalOptionsWidget(this), QIcon(":/img/icons/cog_light.svg") } + { tr("Analysis"), new AnalysisOptionsWidget(this), QIcon(":/img/icons/cog_light.svg") } }; for (auto &c : prefs) { diff --git a/src/widgets/ClassesWidget.cpp b/src/widgets/ClassesWidget.cpp index 4378d064..9185ce03 100644 --- a/src/widgets/ClassesWidget.cpp +++ b/src/widgets/ClassesWidget.cpp @@ -204,24 +204,24 @@ QVariant BinClassesModel::data(const QModelIndex &index, int role) const } } -AnalClassesModel::AnalClassesModel(CutterDockWidget *parent) +AnalysisClassesModel::AnalysisClassesModel(CutterDockWidget *parent) : ClassesModel(parent), attrs(new QMap>) { // Just use a simple refresh deferrer. If an event was triggered in the background, simply // refresh everything later. refreshDeferrer = parent->createRefreshDeferrer([this]() { this->refreshAll(); }); - connect(Core(), &CutterCore::refreshAll, this, &AnalClassesModel::refreshAll); - connect(Core(), &CutterCore::codeRebased, this, &AnalClassesModel::refreshAll); - connect(Core(), &CutterCore::classNew, this, &AnalClassesModel::classNew); - connect(Core(), &CutterCore::classDeleted, this, &AnalClassesModel::classDeleted); - connect(Core(), &CutterCore::classRenamed, this, &AnalClassesModel::classRenamed); - connect(Core(), &CutterCore::classAttrsChanged, this, &AnalClassesModel::classAttrsChanged); + connect(Core(), &CutterCore::refreshAll, this, &AnalysisClassesModel::refreshAll); + connect(Core(), &CutterCore::codeRebased, this, &AnalysisClassesModel::refreshAll); + connect(Core(), &CutterCore::classNew, this, &AnalysisClassesModel::classNew); + connect(Core(), &CutterCore::classDeleted, this, &AnalysisClassesModel::classDeleted); + connect(Core(), &CutterCore::classRenamed, this, &AnalysisClassesModel::classRenamed); + connect(Core(), &CutterCore::classAttrsChanged, this, &AnalysisClassesModel::classAttrsChanged); refreshAll(); } -void AnalClassesModel::refreshAll() +void AnalysisClassesModel::refreshAll() { if (!refreshDeferrer->attemptRefresh(nullptr)) { return; @@ -229,11 +229,11 @@ void AnalClassesModel::refreshAll() beginResetModel(); attrs->clear(); - classes = Core()->getAllAnalClasses(true); // must be sorted + classes = Core()->getAllAnalysisClasses(true); // must be sorted endResetModel(); } -void AnalClassesModel::classNew(const QString &cls) +void AnalysisClassesModel::classNew(const QString &cls) { if (!refreshDeferrer->attemptRefresh(nullptr)) { return; @@ -247,7 +247,7 @@ void AnalClassesModel::classNew(const QString &cls) endInsertRows(); } -void AnalClassesModel::classDeleted(const QString &cls) +void AnalysisClassesModel::classDeleted(const QString &cls) { if (!refreshDeferrer->attemptRefresh(nullptr)) { return; @@ -264,7 +264,7 @@ void AnalClassesModel::classDeleted(const QString &cls) endRemoveRows(); } -void AnalClassesModel::classRenamed(const QString &oldName, const QString &newName) +void AnalysisClassesModel::classRenamed(const QString &oldName, const QString &newName) { if (!refreshDeferrer->attemptRefresh(nullptr)) { return; @@ -296,7 +296,7 @@ void AnalClassesModel::classRenamed(const QString &oldName, const QString &newNa emit dataChanged(index(newRow, 0), index(newRow, 0)); } -void AnalClassesModel::classAttrsChanged(const QString &cls) +void AnalysisClassesModel::classAttrsChanged(const QString &cls) { if (!refreshDeferrer->attemptRefresh(nullptr)) { return; @@ -312,35 +312,35 @@ void AnalClassesModel::classAttrsChanged(const QString &cls) layoutChanged({ persistentIndex }); } -const QVector &AnalClassesModel::getAttrs(const QString &cls) const +const QVector &AnalysisClassesModel::getAttrs(const QString &cls) const { auto it = attrs->find(cls); if (it != attrs->end()) { return it.value(); } - QVector clsAttrs; - QList bases = Core()->getAnalClassBaseClasses(cls); - QList meths = Core()->getAnalClassMethods(cls); - QList vtables = Core()->getAnalClassVTables(cls); + QVector clsAttrs; + QList bases = Core()->getAnalysisClassBaseClasses(cls); + QList meths = Core()->getAnalysisClassMethods(cls); + QList vtables = Core()->getAnalysisClassVTables(cls); clsAttrs.reserve(bases.size() + meths.size() + vtables.size()); - for (const AnalBaseClassDescription &base : bases) { + for (const AnalysisBaseClassDescription &base : bases) { clsAttrs.push_back(Attribute(Attribute::Type::Base, QVariant::fromValue(base))); } - for (const AnalVTableDescription &vtable : vtables) { + for (const AnalysisVTableDescription &vtable : vtables) { clsAttrs.push_back(Attribute(Attribute::Type::VTable, QVariant::fromValue(vtable))); } - for (const AnalMethodDescription &meth : meths) { + for (const AnalysisMethodDescription &meth : meths) { clsAttrs.push_back(Attribute(Attribute::Type::Method, QVariant::fromValue(meth))); } return attrs->insert(cls, clsAttrs).value(); } -QModelIndex AnalClassesModel::index(int row, int column, const QModelIndex &parent) const +QModelIndex AnalysisClassesModel::index(int row, int column, const QModelIndex &parent) const { if (!parent.isValid()) { return createIndex(row, column, (quintptr)0); // root function nodes have id = 0 @@ -350,7 +350,7 @@ QModelIndex AnalClassesModel::index(int row, int column, const QModelIndex &pare (quintptr)parent.row() + 1); // sub-nodes have id = class index + 1 } -QModelIndex AnalClassesModel::parent(const QModelIndex &index) const +QModelIndex AnalysisClassesModel::parent(const QModelIndex &index) const { if (!index.isValid()) { return {}; @@ -363,7 +363,7 @@ QModelIndex AnalClassesModel::parent(const QModelIndex &index) const } } -int AnalClassesModel::rowCount(const QModelIndex &parent) const +int AnalysisClassesModel::rowCount(const QModelIndex &parent) const { if (!parent.isValid()) { // root return classes.count(); @@ -376,17 +376,17 @@ int AnalClassesModel::rowCount(const QModelIndex &parent) const return 0; // below methods/fields } -bool AnalClassesModel::hasChildren(const QModelIndex &parent) const +bool AnalysisClassesModel::hasChildren(const QModelIndex &parent) const { return !parent.isValid() || !parent.parent().isValid(); } -int AnalClassesModel::columnCount(const QModelIndex &) const +int AnalysisClassesModel::columnCount(const QModelIndex &) const { return Columns::COUNT; } -QVariant AnalClassesModel::data(const QModelIndex &index, int role) const +QVariant AnalysisClassesModel::data(const QModelIndex &index, int role) const { if (index.internalId() == 0) { // class row if (index.row() >= classes.count()) { @@ -417,7 +417,7 @@ QVariant AnalClassesModel::data(const QModelIndex &index, int role) const switch (attr.type) { case Attribute::Type::Base: { - AnalBaseClassDescription base = attr.data.value(); + AnalysisBaseClassDescription base = attr.data.value(); switch (role) { case Qt::DisplayRole: switch (index.column()) { @@ -448,7 +448,7 @@ QVariant AnalClassesModel::data(const QModelIndex &index, int role) const break; } case Attribute::Type::Method: { - AnalMethodDescription meth = attr.data.value(); + AnalysisMethodDescription meth = attr.data.value(); switch (role) { case Qt::DisplayRole: switch (index.column()) { @@ -484,7 +484,7 @@ QVariant AnalClassesModel::data(const QModelIndex &index, int role) const break; } case Attribute::Type::VTable: { - AnalVTableDescription vtable = attr.data.value(); + AnalysisVTableDescription vtable = attr.data.value(); switch (role) { case Qt::DisplayRole: switch (index.column()) { @@ -619,7 +619,7 @@ void ClassesWidget::refreshClasses() proxy_model->setSourceModel(nullptr); delete bin_model; bin_model = nullptr; - analysis_model = new AnalClassesModel(this); + analysis_model = new AnalysisClassesModel(this); proxy_model->setSourceModel(analysis_model); } break; @@ -674,8 +674,8 @@ void ClassesWidget::showContextMenu(const QPoint &pt) QString className = index.parent().data(ClassesModel::NameRole).toString(); QString methodName = index.data(ClassesModel::NameRole).toString(); - AnalMethodDescription desc; - if (Core()->getAnalMethod(className, methodName, &desc)) { + AnalysisMethodDescription desc; + if (Core()->getAnalysisMethod(className, methodName, &desc)) { if (desc.vtableOffset >= 0) { menu.addAction(ui->seekToVTableAction); } @@ -690,7 +690,7 @@ void ClassesWidget::on_seekToVTableAction_triggered() QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex(); QString className = index.parent().data(ClassesModel::NameRole).toString(); - QList vtables = Core()->getAnalClassVTables(className); + QList vtables = Core()->getAnalysisClassVTables(className); if (vtables.isEmpty()) { QMessageBox::warning(this, tr("Missing VTable in class"), tr("The class %1 does not have any VTable!").arg(className)); @@ -698,8 +698,8 @@ void ClassesWidget::on_seekToVTableAction_triggered() } QString methodName = index.data(ClassesModel::NameRole).toString(); - AnalMethodDescription desc; - if (!Core()->getAnalMethod(className, methodName, &desc) || desc.vtableOffset < 0) { + AnalysisMethodDescription desc; + if (!Core()->getAnalysisMethod(className, methodName, &desc) || desc.vtableOffset < 0) { return; } diff --git a/src/widgets/ClassesWidget.h b/src/widgets/ClassesWidget.h index 206446cb..cbd3fcad 100644 --- a/src/widgets/ClassesWidget.h +++ b/src/widgets/ClassesWidget.h @@ -90,7 +90,7 @@ public: void setClasses(const QList &classes); }; -class AnalClassesModel : public ClassesModel +class AnalysisClassesModel : public ClassesModel { Q_OBJECT @@ -145,7 +145,7 @@ private: QVariant data(const QModelIndex &index, int role) const override; public: - explicit AnalClassesModel(CutterDockWidget *parent); + explicit AnalysisClassesModel(CutterDockWidget *parent); public slots: void refreshAll(); @@ -198,7 +198,7 @@ private: std::unique_ptr ui; BinClassesModel *bin_model = nullptr; - AnalClassesModel *analysis_model = nullptr; + AnalysisClassesModel *analysis_model = nullptr; ClassesSortFilterProxyModel *proxy_model; }; From 6d2b3a2f3874668802326a032c101e2d8f350d52 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Thu, 16 Sep 2021 13:39:05 +0800 Subject: [PATCH 021/240] Use hash API instead of commands (#2756) --- src/widgets/HexdumpWidget.cpp | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/src/widgets/HexdumpWidget.cpp b/src/widgets/HexdumpWidget.cpp index e636b2aa..ce12be37 100644 --- a/src/widgets/HexdumpWidget.cpp +++ b/src/widgets/HexdumpWidget.cpp @@ -244,16 +244,27 @@ void HexdumpWidget::updateParseWindow(RVA start_address, int size) : ""); } else { // Fill the information tab hashes and entropy - ui->bytesMD5->setText( - Core()->cmdRawAt(QString("ph md5 %1").arg(size), start_address).trimmed()); - ui->bytesSHA1->setText( - Core()->cmdRawAt(QString("ph sha1 %1").arg(size), start_address).trimmed()); - ui->bytesSHA256->setText( - Core()->cmdRawAt(QString("ph sha256 %1").arg(size), start_address).trimmed()); - ui->bytesCRC32->setText( - Core()->cmdRawAt(QString("ph crc32 %1").arg(size), start_address).trimmed()); - ui->bytesEntropy->setText( - Core()->cmdRawAt(QString("ph entropy %1").arg(size), start_address).trimmed()); + RzMsgDigestSize digest_size = 0; + RzCoreLocked core(Core()); + ut64 old_offset = core->offset; + rz_core_seek(core, start_address, true); + ut8 *block = core->block; + char *digest = rz_msg_digest_calculate_small_block_string("md5", block, size, &digest_size, false); + ui->bytesMD5->setText(QString(digest)); + free(digest); + digest = rz_msg_digest_calculate_small_block_string("sha1", block, size, &digest_size, false); + ui->bytesSHA1->setText(QString(digest)); + free(digest); + digest = rz_msg_digest_calculate_small_block_string("sha256", block, size, &digest_size, false); + ui->bytesSHA256->setText(QString(digest)); + free(digest); + digest = rz_msg_digest_calculate_small_block_string("crc32", block, size, &digest_size, false); + ui->bytesCRC32->setText(QString(digest)); + free(digest); + digest = rz_msg_digest_calculate_small_block_string("entropy", block, size, &digest_size, false); + ui->bytesEntropy->setText(QString(digest)); + free(digest); + rz_core_seek(core, old_offset, true); ui->bytesMD5->setCursorPosition(0); ui->bytesSHA1->setCursorPosition(0); ui->bytesSHA256->setCursorPosition(0); From 14c57f5daacc45b940f20b0a8e6e95e24bc75da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Thu, 16 Sep 2021 11:05:47 +0200 Subject: [PATCH 022/240] Update Rizin to latest stable for global variable fixes (#2762) --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index 709a1814..efe394e2 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 709a1814d8302fd3fd905fd60d4a3ee4510ad7c3 +Subproject commit efe394e227098b6360f0c85ef47d45121a58316c From 3e1b3ce8657c8f04805e43dfe571bbfd9ba4ddd6 Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Sat, 18 Sep 2021 10:17:43 +0200 Subject: [PATCH 023/240] TypesInteractionDialog: use RzType API to edit a single type (#2760) --- src/core/Cutter.cpp | 22 ---------------------- src/core/Cutter.h | 19 ------------------- src/dialogs/TypesInteractionDialog.cpp | 14 +++++++++++--- src/dialogs/TypesInteractionDialog.h | 7 +++++++ src/widgets/TypesWidget.cpp | 13 ++++++++++++- 5 files changed, 30 insertions(+), 45 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 439c4db3..454ca6b1 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3571,23 +3571,6 @@ QList CutterCore::getAllTypedefs() return getBaseType(RZ_BASE_TYPE_KIND_TYPEDEF, "Typedef"); } -QString CutterCore::addTypes(const char *str) -{ - CORE_LOCK(); - char *error_msg = nullptr; - int parsed = rz_type_parse_string(core->analysis->typedb, str, &error_msg); - QString error; - - if (!parsed && error_msg) { - error = error_msg; - rz_mem_free(error_msg); - } else if (!parsed) { - error = QString("Failed to load new type %1").arg(str); - } - - return error; -} - QString CutterCore::getTypeAsC(QString name) { CORE_LOCK(); @@ -3602,11 +3585,6 @@ QString CutterCore::getTypeAsC(QString name) return result; } -bool CutterCore::deleteType(const char *typeName) { - CORE_LOCK(); - return rz_type_db_del(core->analysis->typedb, typeName); -} - bool CutterCore::isAddressMapped(RVA addr) { // If value returned by "om. @ addr" is empty means that address is not mapped diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 54a7bb55..687e71c3 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -594,25 +594,6 @@ public: */ QString getTypeAsC(QString name); - /** - * @brief Adds new types - * It first uses the rz_parse_c_string() function from Rizin API to parse the - * supplied C file (in the form of a string). If there were errors, they are displayed. - * If there were no errors, it uses sdb_query_lines() function from Rizin API - * to save the parsed types returned by rz_parse_c_string() - * \param str Contains the definition of the data types - * \return returns an empty QString if there was no error, else returns the error - */ - QString addTypes(const char *str); - QString addTypes(const QString &str) { return addTypes(str.toUtf8().constData()); } - - /** - * @brief Remove a type - * @param typeName Name of the type to remove - */ - bool deleteType(const char *typeName); - bool deleteType(QString typeName) { return deleteType(typeName.toUtf8().constData()); } - /** * @brief Checks if the given address is mapped to a region * @param addr The address to be checked diff --git a/src/dialogs/TypesInteractionDialog.cpp b/src/dialogs/TypesInteractionDialog.cpp index 7f7b6a72..eb2c2284 100644 --- a/src/dialogs/TypesInteractionDialog.cpp +++ b/src/dialogs/TypesInteractionDialog.cpp @@ -22,10 +22,16 @@ TypesInteractionDialog::TypesInteractionDialog(QWidget *parent, bool readOnly) syntaxHighLighter = Config()->createSyntaxHighlighter(ui->plainTextEdit->document()); ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); ui->plainTextEdit->setReadOnly(readOnly); + this->typeName = ""; } TypesInteractionDialog::~TypesInteractionDialog() {} +void TypesInteractionDialog::setTypeName(QString name) +{ + this->typeName = name; +} + void TypesInteractionDialog::on_selectFileButton_clicked() { QString filename = @@ -57,8 +63,11 @@ void TypesInteractionDialog::on_plainTextEdit_textChanged() void TypesInteractionDialog::done(int r) { if (r == QDialog::Accepted) { - QString error = Core()->addTypes(ui->plainTextEdit->toPlainText()); - if (error.isEmpty()) { + RzCoreLocked core(Core()); + bool edited = rz_type_db_edit_base_type( + core->analysis->typedb, this->typeName.toUtf8().constData(), + ui->plainTextEdit->toPlainText().toUtf8().constData()); + if (edited) { emit newTypesLoaded(); QDialog::done(r); return; @@ -67,7 +76,6 @@ void TypesInteractionDialog::done(int r) QMessageBox popup(this); popup.setWindowTitle(tr("Error")); popup.setText(tr("There was some error while loading new types")); - popup.setDetailedText(error); popup.setStandardButtons(QMessageBox::Ok); popup.exec(); } else { diff --git a/src/dialogs/TypesInteractionDialog.h b/src/dialogs/TypesInteractionDialog.h index d45640b3..2c33328e 100644 --- a/src/dialogs/TypesInteractionDialog.h +++ b/src/dialogs/TypesInteractionDialog.h @@ -27,6 +27,12 @@ public: */ void fillTextArea(QString content); + /** + * @brief Set the name of the type that is going to be changed + * @param name - name of the type + */ + void setTypeName(QString name); + private slots: /** * @brief Executed when the user clicks the selectFileButton @@ -50,6 +56,7 @@ private slots: private: std::unique_ptr ui; QSyntaxHighlighter *syntaxHighLighter; + QString typeName; signals: /** diff --git a/src/widgets/TypesWidget.cpp b/src/widgets/TypesWidget.cpp index e5c7a8ec..c2e069a6 100644 --- a/src/widgets/TypesWidget.cpp +++ b/src/widgets/TypesWidget.cpp @@ -76,7 +76,8 @@ QVariant TypesModel::headerData(int section, Qt::Orientation, int role) const bool TypesModel::removeRows(int row, int count, const QModelIndex &parent) { - Core()->deleteType(types->at(row).type); + RzCoreLocked core(Core()); + rz_type_db_del(core->analysis->typedb, types->at(row).type.toUtf8().constData()); beginRemoveRows(parent, row, row + count - 1); while (count--) { types->removeAt(row); @@ -282,9 +283,17 @@ void TypesWidget::on_actionExport_Types_triggered() void TypesWidget::on_actionLoad_New_Types_triggered() { + QModelIndex index = ui->typesTreeView->currentIndex(); + if (!index.isValid()) { + return; + } + + TypeDescription t = index.data(TypesModel::TypeDescriptionRole).value(); + TypesInteractionDialog dialog(this); connect(&dialog, &TypesInteractionDialog::newTypesLoaded, this, &TypesWidget::refreshTypes); dialog.setWindowTitle(tr("Load New Types")); + dialog.setTypeName(t.type); dialog.exec(); } @@ -306,6 +315,7 @@ void TypesWidget::viewType(bool readOnly) dialog.setWindowTitle(tr("View Type: ") + t.type + tr(" (Read Only)")); } dialog.fillTextArea(Core()->getTypeAsC(t.type)); + dialog.setTypeName(t.type); dialog.exec(); } @@ -354,5 +364,6 @@ void TypesWidget::typeItemDoubleClicked(const QModelIndex &index) } dialog.fillTextArea(Core()->getTypeAsC(t.type)); dialog.setWindowTitle(tr("View Type: ") + t.type + tr(" (Read Only)")); + dialog.setTypeName(t.type); dialog.exec(); } From 7e68147eab4daf3c6b1d7e5c7ca975c464179966 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sun, 19 Sep 2021 10:58:08 +0200 Subject: [PATCH 024/240] Fix Bin, IO and Core plugin info (Fix #2764) (#2765) --- src/core/Cutter.cpp | 92 ++++++++++++++---------------- src/core/CutterDescriptions.h | 1 + src/dialogs/RizinPluginsDialog.cpp | 1 + src/dialogs/RizinPluginsDialog.ui | 5 ++ 4 files changed, 50 insertions(+), 49 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 454ca6b1..bc54e6b5 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -2720,72 +2720,66 @@ QStringList CutterCore::getAnalysisPluginNames() QList CutterCore::getRBinPluginDescriptions(const QString &type) { + CORE_LOCK(); QList ret; - - QJsonObject jsonRoot = cmdj("iLj").object(); - for (const QString &key : jsonRoot.keys()) { - if (!type.isNull() && key != type) - continue; - - QJsonArray pluginArray = jsonRoot[key].toArray(); - - for (const QJsonValue &pluginValue : pluginArray) { - QJsonObject pluginObject = pluginValue.toObject(); - - RzBinPluginDescription desc; - - desc.name = pluginObject[RJsonKey::name].toString(); - desc.description = pluginObject[RJsonKey::description].toString(); - desc.license = pluginObject[RJsonKey::license].toString(); - desc.type = key; - - ret.append(desc); - } + RzListIter *it; + RzBinPlugin *bp; + CutterRzListForeach(core->bin->plugins, it, RzBinPlugin, bp) { + RzBinPluginDescription desc; + desc.name = bp->name ? bp->name : ""; + desc.description = bp->desc ? bp->desc : ""; + desc.license = bp->license ? bp->license : ""; + desc.type = "bin"; + ret.append(desc); + } + RzBinXtrPlugin *bx; + CutterRzListForeach(core->bin->binxtrs, it, RzBinXtrPlugin, bx) { + RzBinPluginDescription desc; + desc.name = bx->name ? bx->name : ""; + desc.description = bx->desc ? bx->desc : ""; + desc.license = bx->license ? bx->license : ""; + desc.type = "xtr"; + ret.append(desc); } - return ret; } QList CutterCore::getRIOPluginDescriptions() { + CORE_LOCK(); QList ret; - - QJsonArray plugins = cmdj("oLj").object()["io_plugins"].toArray(); - for (const QJsonValue &pluginValue : plugins) { - QJsonObject pluginObject = pluginValue.toObject(); - - RzIOPluginDescription plugin; - - plugin.name = pluginObject["name"].toString(); - plugin.description = pluginObject["description"].toString(); - plugin.license = pluginObject["license"].toString(); - plugin.permissions = pluginObject["permissions"].toString(); - for (const auto &uri : pluginObject["uris"].toArray()) { - plugin.uris << uri.toString(); + RzListIter *it; + RzIOPlugin *p; + CutterRzListForeach(core->io->plugins, it, RzIOPlugin, p) { + RzIOPluginDescription desc; + desc.name = p->name ? p->name : ""; + desc.description = p->desc ? p->desc : ""; + desc.license = p->license ? p->license : ""; + desc.permissions = + QString("r") + + (p->write ? "w" : "_") + + (p->isdbg ? "d" : "_"); + if (p->uris) { + desc.uris = QString::fromUtf8(p->uris).split(","); } - - ret << plugin; + ret.append(desc); } - return ret; } QList CutterCore::getRCorePluginDescriptions() { + CORE_LOCK(); QList ret; - - QJsonArray plugins = cmdj("Lcj").array(); - for (const QJsonValue &pluginValue : plugins) { - QJsonObject pluginObject = pluginValue.toObject(); - - RzCorePluginDescription plugin; - - plugin.name = pluginObject["Name"].toString(); - plugin.description = pluginObject["Description"].toString(); - - ret << plugin; + RzListIter *it; + RzCorePlugin *p; + CutterRzListForeach(core->plugins, it, RzCorePlugin, p) { + RzCorePluginDescription desc; + desc.name = p->name ? p->name : ""; + desc.description = p->desc ? p->desc : ""; + desc.license = p->license ? p->license : ""; + ret.append(desc); } - return ret; } diff --git a/src/core/CutterDescriptions.h b/src/core/CutterDescriptions.h index aa786185..2fbaeac8 100644 --- a/src/core/CutterDescriptions.h +++ b/src/core/CutterDescriptions.h @@ -194,6 +194,7 @@ struct RzCorePluginDescription { QString name; QString description; + QString license; }; struct RzAsmPluginDescription diff --git a/src/dialogs/RizinPluginsDialog.cpp b/src/dialogs/RizinPluginsDialog.cpp index 8ff12331..cef30200 100644 --- a/src/dialogs/RizinPluginsDialog.cpp +++ b/src/dialogs/RizinPluginsDialog.cpp @@ -36,6 +36,7 @@ RizinPluginsDialog::RizinPluginsDialog(QWidget *parent) QTreeWidgetItem *item = new QTreeWidgetItem(); item->setText(0, plugin.name); item->setText(1, plugin.description); + item->setText(2, plugin.license); ui->RzCoreTreeWidget->addTopLevelItem(item); } ui->RzCoreTreeWidget->sortByColumn(0, Qt::AscendingOrder); diff --git a/src/dialogs/RizinPluginsDialog.ui b/src/dialogs/RizinPluginsDialog.ui index 2492910c..2599b5d5 100644 --- a/src/dialogs/RizinPluginsDialog.ui +++ b/src/dialogs/RizinPluginsDialog.ui @@ -128,6 +128,11 @@ Description + + + License + + From 6b4472f1899479b3ae527f56fc26be278be30eda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 20 Sep 2021 16:35:28 +0200 Subject: [PATCH 025/240] Fix Compatibility with Qt6 (#2767) --- src/widgets/HeapBinsGraphView.cpp | 4 ++-- src/widgets/HeapDockWidget.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/widgets/HeapBinsGraphView.cpp b/src/widgets/HeapBinsGraphView.cpp index 320938ee..0e61ae02 100644 --- a/src/widgets/HeapBinsGraphView.cpp +++ b/src/widgets/HeapBinsGraphView.cpp @@ -195,7 +195,7 @@ void HeapBinsGraphView::addBlock(GraphLayout::GraphBlock block, const QString &t double width = 0; // split text into different lines - auto lines = text.split(QRegExp("[\n]"), QString::SkipEmptyParts); + auto lines = text.split("\n", CUTTER_QT_SKIP_EMPTY_PARTS); // width of the block is the maximum width of a line for (QString &line : lines) { @@ -226,4 +226,4 @@ void HeapBinsGraphView::blockContextMenuRequested(GraphView::GraphBlock &block, addressableItemContextMenu.exec(pos); event->accept(); } -} \ No newline at end of file +} diff --git a/src/widgets/HeapDockWidget.cpp b/src/widgets/HeapDockWidget.cpp index 428fb52a..d30ca0b5 100644 --- a/src/widgets/HeapDockWidget.cpp +++ b/src/widgets/HeapDockWidget.cpp @@ -8,7 +8,7 @@ HeapDockWidget::HeapDockWidget(MainWindow *main) ui->setupUi(this); ui->allocatorSelector->addItem("Glibc Heap"); - ui->verticalLayout->setMargin(0); + ui->verticalLayout->setContentsMargins(0, 0, 0, 0); connect(ui->allocatorSelector, &QComboBox::currentIndexChanged, this, &HeapDockWidget::onAllocatorSelected); From 35de2ae4134ac92d13acb955b8f18bd75f6cd0a3 Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Wed, 22 Sep 2021 10:24:04 +0200 Subject: [PATCH 026/240] Update rizin submodule to 02417f3d3f73522a073020cbdecfef52b8c0cb44 (#2772) --- dist/CMakeLists.txt | 2 +- rizin | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index f72cf261..ade8eee0 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -110,7 +110,7 @@ if(CUTTER_PACKAGE_RZ_GHIDRA) ExternalProject_Add(rz-ghidra GIT_REPOSITORY https://github.com/rizinorg/rz-ghidra #GIT_TAG v0.2.0 - GIT_TAG f2f1e48031442789fc866f7290b63b18b6493771 + GIT_TAG c7a50a2e7c0a95cd52b167c9ee0fa1805223f08e #GIT_TAG dev #GIT_SHALLOW ON # disable this line when using commit hash CONFIGURE_COMMAND "" diff --git a/rizin b/rizin index efe394e2..02417f3d 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit efe394e227098b6360f0c85ef47d45121a58316c +Subproject commit 02417f3d3f73522a073020cbdecfef52b8c0cb44 From 82e88962673fd5332d11591baa8c56326d750600 Mon Sep 17 00:00:00 2001 From: Paul I Date: Wed, 22 Sep 2021 20:19:38 +0300 Subject: [PATCH 027/240] Use API to fetch xrefs in CutterCore::getXRefs() (#2771) --- src/core/Cutter.cpp | 57 +++++++++++++++++---------------------------- 1 file changed, 21 insertions(+), 36 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index bc54e6b5..6b09954a 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3731,51 +3731,36 @@ QList CutterCore::getXRefs(RVA addr, bool to, bool whole_functi { QList xrefList = QList(); - QJsonArray xrefsArray; - - if (to) { - xrefsArray = cmdj("axtj@" + QString::number(addr)).array(); - } else { - xrefsArray = cmdj("axfj@" + QString::number(addr)).array(); + RzList *xrefs = nullptr; + { + CORE_LOCK(); + if (to) { + xrefs = rz_analysis_xrefs_get_to(core->analysis, addr); + } else { + xrefs = rz_analysis_xrefs_get_from(core->analysis, addr); + } } - for (const QJsonValue &value : xrefsArray) { - QJsonObject xrefObject = value.toObject(); + RzListIter *it; + RzAnalysisXRef *xref; + CutterRzListForeach (xrefs, it, RzAnalysisXRef, xref) { + XrefDescription xd; + xd.from = xref->from; + xd.to = xref->to; + xd.type = rz_analysis_xrefs_type_tostring(xref->type); - XrefDescription xref; - - xref.type = xrefObject[RJsonKey::type].toString(); - - if (!filterType.isNull() && filterType != xref.type) + if (!filterType.isNull() && filterType != xd.type) continue; - - xref.from = xrefObject[RJsonKey::from].toVariant().toULongLong(); - if (!to) { - xref.from_str = RzAddressString(xref.from); - } else { - QString fcn = xrefObject[RJsonKey::fcn_name].toString(); - if (!fcn.isEmpty()) { - RVA fcnAddr = xrefObject[RJsonKey::fcn_addr].toVariant().toULongLong(); - xref.from_str = fcn + " + 0x" + QString::number(xref.from - fcnAddr, 16); - } else { - xref.from_str = RzAddressString(xref.from); - } - } - - if (!whole_function && !to && xref.from != addr) { + if (!whole_function && !to && xd.from != addr) { continue; } - if (to && !xrefObject.contains(RJsonKey::to)) { - xref.to = addr; - } else { - xref.to = xrefObject[RJsonKey::to].toVariant().toULongLong(); - } - xref.to_str = Core()->cmdRaw(QString("fd %1").arg(xref.to)).trimmed(); + xd.from_str = RzAddressString(xd.from); + xd.to_str = Core()->cmdRaw(QString("fd %1").arg(xd.to)).trimmed(); - xrefList << xref; + xrefList << xd; } - + rz_list_free(xrefs); return xrefList; } From 48c884c3d6cdcc65dbddb355ac7772f766d7b58c Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Thu, 23 Sep 2021 01:20:20 +0800 Subject: [PATCH 028/240] Fix wrong initialization order in ArenaInfoDialog (#2774) --- src/dialogs/ArenaInfoDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dialogs/ArenaInfoDialog.cpp b/src/dialogs/ArenaInfoDialog.cpp index 3d389d51..977f58fe 100644 --- a/src/dialogs/ArenaInfoDialog.cpp +++ b/src/dialogs/ArenaInfoDialog.cpp @@ -2,7 +2,7 @@ #include "ui_ArenaInfoDialog.h" ArenaInfoDialog::ArenaInfoDialog(Arena &arena, QWidget *parent) - : arena(arena), QDialog(parent), ui(new Ui::ArenaInfoDialog) + : QDialog(parent), ui(new Ui::ArenaInfoDialog), arena(arena) { ui->setupUi(this); setWindowTitle("Arena @ " + RzAddressString(arena.offset)); From 99070e86b950b9862dd3f8bc820de71f15ee2b0d Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Thu, 23 Sep 2021 10:15:03 +0200 Subject: [PATCH 029/240] Use new Rizin API instead of cmdRaw/cmdRawAt (#2770) * Use new Rizin API instead of cmdRaw/cmdRawAt * add CutterRzListForeach as a foreach-keyword for clang-format --- _clang-format | 1 + src/common/AnalysisTask.cpp | 3 +- src/core/Cutter.cpp | 78 ++++++++++++++++------------- src/dialogs/EditVariablesDialog.cpp | 24 +++++++-- src/dialogs/LinkTypeDialog.cpp | 23 +++++---- src/widgets/HexWidget.cpp | 40 +++++++++------ 6 files changed, 105 insertions(+), 64 deletions(-) diff --git a/_clang-format b/_clang-format index 65079d08..67f84f00 100644 --- a/_clang-format +++ b/_clang-format @@ -66,6 +66,7 @@ ForEachMacros: - Q_FOREVER - QBENCHMARK - QBENCHMARK_ONCE + - CutterRzListForeach IncludeBlocks: Preserve IncludeCategories: - Regex: '^"(llvm|llvm-c|clang|clang-c)/' diff --git a/src/common/AnalysisTask.cpp b/src/common/AnalysisTask.cpp index 5752a470..75e90395 100644 --- a/src/common/AnalysisTask.cpp +++ b/src/common/AnalysisTask.cpp @@ -64,7 +64,8 @@ void AnalysisTask::runTask() } if (!options.os.isNull()) { - Core()->cmdRaw("e asm.os=" + options.os); + RzCoreLocked core(Core()); + rz_config_set(core->config, "asm.os", options.os.toUtf8().constData()); } if (!options.pdbFile.isNull()) { diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 6b09954a..a2d81fb7 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -390,7 +390,7 @@ bool CutterCore::isRedirectableDebugee() RzList *descs = rz_id_storage_list(core->io->files); RzListIter *it; RzIODesc *desc; - CutterRzListForeach(descs, it, RzIODesc, desc) { + CutterRzListForeach (descs, it, RzIODesc, desc) { QString URI = QString(desc->uri); if (URI.contains("ptrace") | URI.contains("mach")) { return true; @@ -771,7 +771,12 @@ void CutterCore::editBytes(RVA addr, const QString &bytes) void CutterCore::editBytesEndian(RVA addr, const QString &bytes) { - cmdRawAt(QString("wv %1").arg(bytes), addr); + CORE_LOCK(); + ut64 value = rz_num_math(core->num, bytes.toUtf8().constData()); + if (core->num->nc.errors) { + return; + } + rz_core_write_value_at(core, addr, value, 0); emit stackChanged(); } @@ -938,7 +943,12 @@ void CutterCore::seekAndShow(QString offset) void CutterCore::seek(QString thing) { - cmdRaw(QString("s %1").arg(thing)); + CORE_LOCK(); + ut64 addr = rz_num_math(core->num, thing.toUtf8().constData()); + if (core->num->nc.errors) { + return; + } + rz_core_seek_and_save(core, addr, true); updateSeek(); } @@ -1365,8 +1375,8 @@ RefDescription CutterCore::formatRefDesc(QJsonObject refItem) break; } if (!refItem["value"].isNull()) { - appendVar(desc.ref, RzAddressString(refItem["value"].toVariant().toULongLong()), " ", - ""); + appendVar(desc.ref, RzAddressString(refItem["value"].toVariant().toULongLong()), + " ", ""); } refItem = refItem["ref"].toObject(); } while (!refItem.empty()); @@ -1580,8 +1590,7 @@ QVector CutterCore::getHeapChunks(RVA arena_addr) RzList *chunks = rz_heap_chunks_list(core, m_arena); RzListIter *iter; RzHeapChunkListItem *data; - CutterRzListForeach(chunks, iter, RzHeapChunkListItem, data) - { + CutterRzListForeach (chunks, iter, RzHeapChunkListItem, data) { Chunk chunk; chunk.offset = data->addr; chunk.size = (int)data->size; @@ -1608,8 +1617,7 @@ QVector CutterCore::getArenas() RzList *arenas = rz_heap_arenas_list(core); RzListIter *iter; RzArenaListItem *data; - CutterRzListForeach(arenas, iter, RzArenaListItem, data) - { + CutterRzListForeach (arenas, iter, RzArenaListItem, data) { Arena arena; arena.offset = data->addr; arena.type = QString(data->type); @@ -1670,8 +1678,7 @@ QVector CutterCore::getHeapBins(ut64 arena_addr) RzList *tcache_bins = rz_heap_tcache_content(core, arena_addr); RzListIter *iter; RzHeapBin *bin; - CutterRzListForeach(tcache_bins, iter, RzHeapBin, bin) - { + CutterRzListForeach (tcache_bins, iter, RzHeapBin, bin) { if (!bin) { continue; } @@ -1918,7 +1925,7 @@ void CutterCore::attachRemote(const QString &uri) RzList *descs = rz_id_storage_list(core->io->files); RzListIter *it; RzIODesc *desc; - CutterRzListForeach(descs, it, RzIODesc, desc) { + CutterRzListForeach (descs, it, RzIODesc, desc) { QString fileUri = QString(desc->uri); if (!fileUri.compare(uri)) { connected = true; @@ -2030,7 +2037,7 @@ void CutterCore::stopDebug() RzList *descs = rz_id_storage_list(core->io->files); RzListIter *it; RzIODesc *desc; - CutterRzListForeach(descs, it, RzIODesc, desc) { + CutterRzListForeach (descs, it, RzIODesc, desc) { QString URI = QString(desc->uri); if (URI.contains("ptrace")) { ptraceFiles += "o-" + QString::number(desc->fd) + ";"; @@ -2689,7 +2696,9 @@ QList CutterCore::getSeekHistory() RzListIter *it; RzCoreSeekItem *undo; RzList *list = rz_core_seek_list(core); - CutterRzListForeach(list, it, RzCoreSeekItem, undo) { ret << undo->offset; } + CutterRzListForeach (list, it, RzCoreSeekItem, undo) { + ret << undo->offset; + } return ret; } @@ -2701,7 +2710,9 @@ QStringList CutterCore::getAsmPluginNames() QStringList ret; RzAsmPlugin *ap; - CutterRzListForeach(core->rasm->plugins, it, RzAsmPlugin, ap) { ret << ap->name; } + CutterRzListForeach (core->rasm->plugins, it, RzAsmPlugin, ap) { + ret << ap->name; + } return ret; } @@ -2713,7 +2724,9 @@ QStringList CutterCore::getAnalysisPluginNames() QStringList ret; RzAnalysisPlugin *ap; - CutterRzListForeach(core->analysis->plugins, it, RzAnalysisPlugin, ap) { ret << ap->name; } + CutterRzListForeach (core->analysis->plugins, it, RzAnalysisPlugin, ap) { + ret << ap->name; + } return ret; } @@ -2724,7 +2737,7 @@ QList CutterCore::getRBinPluginDescriptions(const QStrin QList ret; RzListIter *it; RzBinPlugin *bp; - CutterRzListForeach(core->bin->plugins, it, RzBinPlugin, bp) { + CutterRzListForeach (core->bin->plugins, it, RzBinPlugin, bp) { RzBinPluginDescription desc; desc.name = bp->name ? bp->name : ""; desc.description = bp->desc ? bp->desc : ""; @@ -2733,7 +2746,7 @@ QList CutterCore::getRBinPluginDescriptions(const QStrin ret.append(desc); } RzBinXtrPlugin *bx; - CutterRzListForeach(core->bin->binxtrs, it, RzBinXtrPlugin, bx) { + CutterRzListForeach (core->bin->binxtrs, it, RzBinXtrPlugin, bx) { RzBinPluginDescription desc; desc.name = bx->name ? bx->name : ""; desc.description = bx->desc ? bx->desc : ""; @@ -2750,15 +2763,12 @@ QList CutterCore::getRIOPluginDescriptions() QList ret; RzListIter *it; RzIOPlugin *p; - CutterRzListForeach(core->io->plugins, it, RzIOPlugin, p) { + CutterRzListForeach (core->io->plugins, it, RzIOPlugin, p) { RzIOPluginDescription desc; desc.name = p->name ? p->name : ""; desc.description = p->desc ? p->desc : ""; desc.license = p->license ? p->license : ""; - desc.permissions = - QString("r") + - (p->write ? "w" : "_") + - (p->isdbg ? "d" : "_"); + desc.permissions = QString("r") + (p->write ? "w" : "_") + (p->isdbg ? "d" : "_"); if (p->uris) { desc.uris = QString::fromUtf8(p->uris).split(","); } @@ -2773,7 +2783,7 @@ QList CutterCore::getRCorePluginDescriptions() QList ret; RzListIter *it; RzCorePlugin *p; - CutterRzListForeach(core->plugins, it, RzCorePlugin, p) { + CutterRzListForeach (core->plugins, it, RzCorePlugin, p) { RzCorePluginDescription desc; desc.name = p->name ? p->name : ""; desc.description = p->desc ? p->desc : ""; @@ -2790,8 +2800,7 @@ QList CutterCore::getRAsmPluginDescriptions() QList ret; RzAsmPlugin *ap; - CutterRzListForeach(core->rasm->plugins, it, RzAsmPlugin, ap) - { + CutterRzListForeach (core->rasm->plugins, it, RzAsmPlugin, ap) { RzAsmPluginDescription plugin; plugin.name = ap->name; @@ -2817,8 +2826,7 @@ QList CutterCore::getAllFunctions() RzListIter *iter; RzAnalysisFunction *fcn; - CutterRzListForeach(core->analysis->fcns, iter, RzAnalysisFunction, fcn) - { + CutterRzListForeach (core->analysis->fcns, iter, RzAnalysisFunction, fcn) { FunctionDescription function; function.offset = fcn->addr; function.linearSize = rz_analysis_function_linear_size(fcn); @@ -2898,8 +2906,7 @@ QList CutterCore::getAllSymbols() RzBinSymbol *bs; if (core && core->bin && core->bin->cur && core->bin->cur->o) { - CutterRzListForeach(core->bin->cur->o->symbols, it, RzBinSymbol, bs) - { + CutterRzListForeach (core->bin->cur->o->symbols, it, RzBinSymbol, bs) { QString type = QString(bs->bind) + " " + QString(bs->type); SymbolDescription symbol; symbol.vaddr = bs->vaddr; @@ -2912,8 +2919,7 @@ QList CutterCore::getAllSymbols() /* list entrypoints as symbols too */ int n = 0; RzBinAddr *entry; - CutterRzListForeach(core->bin->cur->o->entries, it, RzBinAddr, entry) - { + CutterRzListForeach (core->bin->cur->o->entries, it, RzBinAddr, entry) { SymbolDescription symbol; symbol.vaddr = entry->vaddr; symbol.name = QString("entry") + QString::number(n++); @@ -3415,7 +3421,8 @@ void CutterCore::deleteClass(const QString &cls) rz_analysis_class_delete(core->analysis, cls.toUtf8().constData()); } -bool CutterCore::getAnalysisMethod(const QString &cls, const QString &meth, AnalysisMethodDescription *desc) +bool CutterCore::getAnalysisMethod(const QString &cls, const QString &meth, + AnalysisMethodDescription *desc) { CORE_LOCK(); RzAnalysisMethod analysisMeth; @@ -3443,7 +3450,7 @@ void CutterCore::setAnalysisMethod(const QString &className, const AnalysisMetho } void CutterCore::renameAnalysisMethod(const QString &className, const QString &oldMethodName, - const QString &newMethodName) + const QString &newMethodName) { CORE_LOCK(); rz_analysis_class_method_rename(core->analysis, className.toUtf8().constData(), @@ -3855,7 +3862,8 @@ void CutterCore::triggerFunctionRenamed(const RVA offset, const QString &newName void CutterCore::loadPDB(const QString &file) { - cmdRaw("idp " + sanitizeStringForCommand(file)); + CORE_LOCK(); + rz_core_bin_pdb_load(core, file.toUtf8().constData()); } QList CutterCore::disassembleLines(RVA offset, int lines) diff --git a/src/dialogs/EditVariablesDialog.cpp b/src/dialogs/EditVariablesDialog.cpp index 08966071..5525048f 100644 --- a/src/dialogs/EditVariablesDialog.cpp +++ b/src/dialogs/EditVariablesDialog.cpp @@ -55,7 +55,25 @@ void EditVariablesDialog::applyFields() } VariableDescription desc = ui->dropdownLocalVars->currentData().value(); - Core()->cmdRaw(QString("afvt %1 %2").arg(desc.name).arg(ui->typeComboBox->currentText())); + RzCoreLocked core(Core()); + RzAnalysisFunction *fcn = Core()->functionIn(core->offset); + if (!fcn) { + return; + } + + RzAnalysisVar *v = rz_analysis_function_get_var_byname(fcn, desc.name.toUtf8().constData()); + if (!v) { + return; + } + + char *error_msg = NULL; + RzType *v_type = rz_type_parse_string_single( + core->analysis->typedb->parser, ui->typeComboBox->currentText().toUtf8().constData(), + &error_msg); + if (!v_type || error_msg) { + return; + } + rz_analysis_var_set_type(v, v_type); // TODO Remove all those replace once rizin command parser is fixed QString newName = ui->nameEdit->text() @@ -84,7 +102,8 @@ void EditVariablesDialog::updateFields() ui->typeComboBox->setCurrentText(desc.type); } -static void addTypeDescriptionsToComboBox(QComboBox *comboBox, QList list) { +static void addTypeDescriptionsToComboBox(QComboBox *comboBox, QList list) +{ for (const TypeDescription &thisType : list) { comboBox->addItem(thisType.type); } @@ -97,5 +116,4 @@ void EditVariablesDialog::populateTypesComboBox() addTypeDescriptionsToComboBox(ui->typeComboBox, Core()->getAllPrimitiveTypes()); addTypeDescriptionsToComboBox(ui->typeComboBox, Core()->getAllEnums()); addTypeDescriptionsToComboBox(ui->typeComboBox, Core()->getAllTypedefs()); - } diff --git a/src/dialogs/LinkTypeDialog.cpp b/src/dialogs/LinkTypeDialog.cpp index fc1c95ea..6d2a9110 100644 --- a/src/dialogs/LinkTypeDialog.cpp +++ b/src/dialogs/LinkTypeDialog.cpp @@ -56,10 +56,14 @@ void LinkTypeDialog::done(int r) QString type = ui->structureTypeComboBox->currentText(); if (type == tr("(No Type)")) { // Delete link - Core()->cmdRaw("tl- " + address); + RzCoreLocked core(Core()); + ut64 addr = rz_num_math(core->num, address.toUtf8().constData()); + rz_analysis_type_unlink(core->analysis, addr); } else { // Create link - Core()->cmdRaw(QString("tl %1 = %2").arg(type).arg(address)); + RzCoreLocked core(Core()); + ut64 addr = rz_num_math(core->num, address.toUtf8().constData()); + rz_core_types_link(core, type.toUtf8().constData(), addr); } QDialog::done(r); @@ -84,16 +88,17 @@ QString LinkTypeDialog::findLinkedType(RVA address) return QString(); } - QString ret = Core()->cmdRaw(QString("tls %1").arg(address)); - if (ret.isEmpty()) { - // return empty string since the current address is not linked to a type + RzCoreLocked core(Core()); + RzType *link = rz_analysis_type_link_at(core->analysis, address); + if (!link) { + return QString(); + } + RzBaseType *base = rz_type_get_base_type(core->analysis->typedb, link); + if (!base) { return QString(); } - // Extract the given type from returned data - // TODO: Implement "tlsj" in Rizin or some other function to directly get linked type - QString s = ret.section(QLatin1Char('\n'), 0, 0); - return s.mid(1, s.size() - 2); + return QString(base->name); } void LinkTypeDialog::on_exprLineEdit_textChanged(const QString &text) diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index 914cb6c3..784528a9 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -704,7 +704,8 @@ void HexWidget::w_writeString() d.setInputMode(QInputDialog::InputMode::TextInput); QString str = d.getText(this, tr("Write string"), tr("String:"), QLineEdit::Normal, "", &ok); if (ok && !str.isEmpty()) { - Core()->cmdRawAt(QString("w %1").arg(str), getLocationAddress()); + RzCoreLocked core(Core()); + rz_core_write_string_at(core, getLocationAddress(), str.toUtf8().constData()); refresh(); } } @@ -719,12 +720,13 @@ void HexWidget::w_increaseDecrease() if (ret == QDialog::Rejected) { return; } - QString mode = d.getMode() == IncrementDecrementDialog::Increase ? "+" : "-"; - Core()->cmdRawAt(QString("w%1%2 %3") - .arg(QString::number(d.getNBytes())) - .arg(mode) - .arg(QString::number(d.getValue())), - getLocationAddress()); + int64_t value = (int64_t)d.getValue(); + uint8_t sz = d.getNBytes(); + if (!d.getMode() == IncrementDecrementDialog::Increase) { + value *= -1; + } + RzCoreLocked core(Core()); + rz_core_write_value_inc_at(core, getLocationAddress(), value, sz); refresh(); } @@ -741,10 +743,14 @@ void HexWidget::w_writeZeros() size = static_cast(selection.size()); } - QString str = QString::number( - d.getInt(this, tr("Write zeros"), tr("Number of zeros:"), size, 1, 0x7FFFFFFF, 1, &ok)); - if (ok && !str.isEmpty()) { - Core()->cmdRawAt(QString("w0 %1").arg(str), getLocationAddress()); + int len = + d.getInt(this, tr("Write zeros"), tr("Number of zeros:"), size, 1, 0x7FFFFFFF, 1, &ok); + if (ok) { + RzCoreLocked core(Core()); + uint8_t *buf = (uint8_t *)calloc(len, sizeof(uint8_t)); + rz_core_write_at(core, getLocationAddress(), buf, len); + free(buf); + refresh(); } } @@ -759,10 +765,9 @@ void HexWidget::w_write64() if (ret == QDialog::Rejected) { return; } - QString mode = d.getMode() == Base64EnDecodedWriteDialog::Encode ? "e" : "d"; QByteArray str = d.getData(); - if (mode == "d" + if (d.getMode() == Base64EnDecodedWriteDialog::Decode && (QString(str).contains(QRegularExpression("[^a-zA-Z0-9+/=]")) || str.length() % 4 != 0 || str.isEmpty())) { QMessageBox::critical( @@ -772,9 +777,12 @@ void HexWidget::w_write64() return; } - Core()->cmdRawAt(QString("w6%1 %2").arg(mode).arg( - (mode == "e" ? str.toHex() : str).toStdString().c_str()), - getLocationAddress()); + RzCoreLocked core(Core()); + if (d.getMode() == Base64EnDecodedWriteDialog::Encode) { + rz_core_write_base64_at(core, getLocationAddress(), str.toHex().constData()); + } else { + rz_core_write_base64d_at(core, getLocationAddress(), str.constData()); + } refresh(); } From dada19cf1c6d9ceb9cb7bb207faf0e126d04ccdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Thu, 23 Sep 2021 16:09:51 +0200 Subject: [PATCH 030/240] Various improvements for native macOS UI (#2776) --- src/CutterApplication.cpp | 4 + src/common/Configuration.cpp | 8 + src/dialogs/InitialOptionsDialog.ui | 6 + src/img/cutter_macos_simple.svg | 225 +++++++++++++++++++++++ src/resources.qrc | 1 + src/themes/native/macos-close-dark.svg | 23 +++ src/themes/native/macos-close-light.svg | 23 +++ src/themes/native/macos-float-dark.svg | 16 ++ src/themes/native/macos-float-light.svg | 16 ++ src/themes/native/native-macos-dark.qss | 31 ++++ src/themes/native/native-macos-light.qss | 30 +++ src/themes/native/native.qrc | 6 + 12 files changed, 389 insertions(+) create mode 100644 src/img/cutter_macos_simple.svg create mode 100644 src/themes/native/macos-close-dark.svg create mode 100644 src/themes/native/macos-close-light.svg create mode 100644 src/themes/native/macos-float-dark.svg create mode 100644 src/themes/native/macos-float-light.svg create mode 100644 src/themes/native/native-macos-dark.qss create mode 100644 src/themes/native/native-macos-light.qss diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index d0134c91..ba06c112 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -43,7 +43,11 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc { // Setup application information setApplicationVersion(CUTTER_VERSION_FULL); +#ifdef Q_OS_MACOS + setWindowIcon(QIcon(":/img/cutter_macos_simple.svg")); +#else setWindowIcon(QIcon(":/img/cutter.svg")); +#endif #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) setAttribute(Qt::AA_UseHighDpiPixmaps); // always enabled on Qt >= 6.0.0 #endif diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 133b0610..764ecdb5 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -288,6 +288,14 @@ void Configuration::loadNativeStylesheet() f.open(QFile::ReadOnly | QFile::Text); QTextStream ts(&f); QString stylesheet = ts.readAll(); +#ifdef Q_OS_MACOS + QFile mf(nativeWindowIsDark() ? ":native/native-macos-dark.qss" : ":native/native-macos-light.qss"); + if (mf.exists()) { + mf.open(QFile::ReadOnly | QFile::Text); + QTextStream mts(&mf); + stylesheet += "\n" + mts.readAll(); + } +#endif qApp->setStyleSheet(stylesheet); } diff --git a/src/dialogs/InitialOptionsDialog.ui b/src/dialogs/InitialOptionsDialog.ui index 3b8cc363..481c409c 100644 --- a/src/dialogs/InitialOptionsDialog.ui +++ b/src/dialogs/InitialOptionsDialog.ui @@ -188,6 +188,12 @@ 0 + + + 0 + 24 + + 0 diff --git a/src/img/cutter_macos_simple.svg b/src/img/cutter_macos_simple.svg new file mode 100644 index 00000000..f7419c92 --- /dev/null +++ b/src/img/cutter_macos_simple.svg @@ -0,0 +1,225 @@ + + + macOS-icon + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + macOS-icon + + + + diff --git a/src/resources.qrc b/src/resources.qrc index 0f80520b..79d02948 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -107,6 +107,7 @@ img/cutter_plain.svg img/cutter_white_plain.svg img/cutter.svg + img/cutter_macos_simple.svg img/icons/copy.svg img/icons/delete.svg img/icons/previous.svg diff --git a/src/themes/native/macos-close-dark.svg b/src/themes/native/macos-close-dark.svg new file mode 100644 index 00000000..55093cde --- /dev/null +++ b/src/themes/native/macos-close-dark.svg @@ -0,0 +1,23 @@ + + + + + + + + + diff --git a/src/themes/native/macos-close-light.svg b/src/themes/native/macos-close-light.svg new file mode 100644 index 00000000..75c1cb95 --- /dev/null +++ b/src/themes/native/macos-close-light.svg @@ -0,0 +1,23 @@ + + + + + + + + + diff --git a/src/themes/native/macos-float-dark.svg b/src/themes/native/macos-float-dark.svg new file mode 100644 index 00000000..32cfad91 --- /dev/null +++ b/src/themes/native/macos-float-dark.svg @@ -0,0 +1,16 @@ + + + + + diff --git a/src/themes/native/macos-float-light.svg b/src/themes/native/macos-float-light.svg new file mode 100644 index 00000000..3d7ba826 --- /dev/null +++ b/src/themes/native/macos-float-light.svg @@ -0,0 +1,16 @@ + + + + + diff --git a/src/themes/native/native-macos-dark.qss b/src/themes/native/native-macos-dark.qss new file mode 100644 index 00000000..2f3f630c --- /dev/null +++ b/src/themes/native/native-macos-dark.qss @@ -0,0 +1,31 @@ +/* +Cocoa has no notion of Dock Widgets so Qt has to craft them itself, +but the default appearance is awful! +So let's try to make them as native as possible. +*/ +QDockWidget::title { + text-align: center; + background: palette(window); +} + +QDockWidget { + titlebar-close-icon: url(:/native/macos-close-dark.svg); + titlebar-normal-icon: url(:/native/macos-float-dark.svg); +} + +QDockWidget::close-button, +QDockWidget::float-button { + border: 1px solid transparent; + border-radius: 10px; + background: transparent; +} + +QDockWidget::close-button:hover, +QDockWidget::float-button:hover { + background: rgba(255, 255, 255, 10); +} + +QDockWidget::close-button:pressed, +QDockWidget::float-button:pressed { + background: rgba(255, 255, 255, 10); +} diff --git a/src/themes/native/native-macos-light.qss b/src/themes/native/native-macos-light.qss new file mode 100644 index 00000000..efb9e30f --- /dev/null +++ b/src/themes/native/native-macos-light.qss @@ -0,0 +1,30 @@ +/* +Cocoa has no notion of Dock Widgets so Qt has to craft them itself, +but the default appearance is awful! +So let's try to make them as native as possible. +*/ +QDockWidget::title { + text-align: center; +} + +QDockWidget { + titlebar-close-icon: url(:/native/macos-close-light.svg); + titlebar-normal-icon: url(:/native/macos-float-light.svg); +} + +QDockWidget::close-button, +QDockWidget::float-button { + border: 1px solid transparent; + border-radius: 10px; + background: transparent; +} + +QDockWidget::close-button:hover, +QDockWidget::float-button:hover { + background: rgba(0, 0, 0, 10); +} + +QDockWidget::close-button:pressed, +QDockWidget::float-button:pressed { + background: rgba(0, 0, 0, 10); +} diff --git a/src/themes/native/native.qrc b/src/themes/native/native.qrc index c81e59a7..d1eeaffb 100644 --- a/src/themes/native/native.qrc +++ b/src/themes/native/native.qrc @@ -1,5 +1,11 @@ native.qss + native-macos-dark.qss + macos-close-dark.svg + macos-float-dark.svg + native-macos-light.qss + macos-close-light.svg + macos-float-light.svg From 3ba7363f99aaa7e7411f1bf59c2c34b8263fd3b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Thu, 23 Sep 2021 17:57:51 +0200 Subject: [PATCH 031/240] Remove Type Link features in light of global variables (#2775) --- .../menus/disassembly-context-menu.rst | 9 -- docs/source/user-docs/shortcuts.rst | 2 - src/CMakeLists.txt | 3 - src/dialogs/LinkTypeDialog.cpp | 114 ----------------- src/dialogs/LinkTypeDialog.h | 66 ---------- src/dialogs/LinkTypeDialog.ui | 117 ------------------ src/menus/DisassemblyContextMenu.cpp | 20 --- src/menus/DisassemblyContextMenu.h | 14 --- src/widgets/TypesWidget.cpp | 17 --- src/widgets/TypesWidget.h | 6 - src/widgets/TypesWidget.ui | 5 - 11 files changed, 373 deletions(-) delete mode 100644 src/dialogs/LinkTypeDialog.cpp delete mode 100644 src/dialogs/LinkTypeDialog.h delete mode 100644 src/dialogs/LinkTypeDialog.ui diff --git a/docs/source/user-docs/menus/disassembly-context-menu.rst b/docs/source/user-docs/menus/disassembly-context-menu.rst index 5f114f68..15ced58d 100644 --- a/docs/source/user-docs/menus/disassembly-context-menu.rst +++ b/docs/source/user-docs/menus/disassembly-context-menu.rst @@ -103,15 +103,6 @@ Set Structure Offset **Steps:** -> Structure offset -Link a Type to Address ----------------------------------------- -**Description:** You can link type, enum or structure to a specific address. Types, structures and enums can be defined in the Types widget. - -**Steps:** Right-click on an instruction and choose ``Link Type to Address``. - -**Shortcut:** :kbd:`L` - - Show Cross References ---------------------------------------- **Description:** Show X-Refs from and to the specific location. This option will open Cutter's X-Refs dialog in which you will be able to see a list of X-Refs from and to the selected location, in addition to a preview of each cross-reference to quickly inspect the different usages. diff --git a/docs/source/user-docs/shortcuts.rst b/docs/source/user-docs/shortcuts.rst index 9f95a185..68c2dc2b 100644 --- a/docs/source/user-docs/shortcuts.rst +++ b/docs/source/user-docs/shortcuts.rst @@ -62,8 +62,6 @@ Disassembly View Shortcuts +-------------+----------------------------------+ | Y | Edit/rename local variables | +-------------+----------------------------------+ -| L | Link a type/struct to address | -+-------------+----------------------------------+ | A | Set current address to String | +-------------+----------------------------------+ | C | Set current address to Code | diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a8cead25..651af4bb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -109,7 +109,6 @@ set(SOURCES plugins/PluginManager.cpp common/BasicBlockHighlighter.cpp common/BasicInstructionHighlighter.cpp - dialogs/LinkTypeDialog.cpp widgets/ColorPicker.cpp common/ColorThemeWorker.cpp widgets/ColorThemeComboBox.cpp @@ -271,7 +270,6 @@ set(HEADER_FILES widgets/MemoryDockWidget.h widgets/ColorThemeListView.h dialogs/preferences/ColorThemeEditDialog.h - dialogs/LinkTypeDialog.h common/BugReporting.h common/HighDpiPixmap.h widgets/GraphLayout.h @@ -365,7 +363,6 @@ set(UI_FILES dialogs/EditMethodDialog.ui dialogs/TypesInteractionDialog.ui widgets/SdbWidget.ui - dialogs/LinkTypeDialog.ui widgets/ColorPicker.ui dialogs/preferences/ColorThemeEditDialog.ui widgets/ListDockWidget.ui diff --git a/src/dialogs/LinkTypeDialog.cpp b/src/dialogs/LinkTypeDialog.cpp deleted file mode 100644 index 6d2a9110..00000000 --- a/src/dialogs/LinkTypeDialog.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "LinkTypeDialog.h" -#include "ui_LinkTypeDialog.h" - -LinkTypeDialog::LinkTypeDialog(QWidget *parent) : QDialog(parent), ui(new Ui::LinkTypeDialog) -{ - addrValid = false; - - ui->setupUi(this); - - setWindowTitle(tr("Link type to address")); - - // Populate the structureTypeComboBox - ui->structureTypeComboBox->addItem(tr("(No Type)")); - for (const TypeDescription &thisType : Core()->getAllStructs()) { - ui->structureTypeComboBox->addItem(thisType.type); - } -} - -LinkTypeDialog::~LinkTypeDialog() -{ - delete ui; -} - -void LinkTypeDialog::setDefaultType(const QString &type) -{ - int index = ui->structureTypeComboBox->findText(type); - if (index != -1) { - // index is valid so set is as the default - ui->structureTypeComboBox->setCurrentIndex(index); - } -} - -bool LinkTypeDialog::setDefaultAddress(const QString &address) -{ - // setting the text here will trigger on_exprLineEdit_textChanged, which will update addrValid - ui->exprLineEdit->setText(address); - - if (!addrValid) { - return false; - } - - // check if the current address is already linked to a type and set it as default - QString type = findLinkedType(Core()->math(ui->addressLineEdit->text())); - if (!type.isEmpty()) { - setDefaultType(type); - } - return true; -} - -void LinkTypeDialog::done(int r) -{ - if (r == QDialog::Accepted) { - QString address = ui->addressLineEdit->text(); - if (Core()->isAddressMapped(Core()->math(address))) { - // Address is valid so link the type to the address - QString type = ui->structureTypeComboBox->currentText(); - if (type == tr("(No Type)")) { - // Delete link - RzCoreLocked core(Core()); - ut64 addr = rz_num_math(core->num, address.toUtf8().constData()); - rz_analysis_type_unlink(core->analysis, addr); - } else { - // Create link - RzCoreLocked core(Core()); - ut64 addr = rz_num_math(core->num, address.toUtf8().constData()); - rz_core_types_link(core, type.toUtf8().constData(), addr); - } - QDialog::done(r); - - // Seek to the specified address - Core()->seekAndShow(address); - - // Refresh the views - emit Core()->refreshCodeViews(); - return; - } - - // Address is invalid so display error message - QMessageBox::warning(this, tr("Error"), tr("The given address is invalid")); - } else { - QDialog::done(r); - } -} - -QString LinkTypeDialog::findLinkedType(RVA address) -{ - if (address == RVA_INVALID) { - return QString(); - } - - RzCoreLocked core(Core()); - RzType *link = rz_analysis_type_link_at(core->analysis, address); - if (!link) { - return QString(); - } - RzBaseType *base = rz_type_get_base_type(core->analysis->typedb, link); - if (!base) { - return QString(); - } - - return QString(base->name); -} - -void LinkTypeDialog::on_exprLineEdit_textChanged(const QString &text) -{ - RVA addr = Core()->math(text); - if (Core()->isAddressMapped(addr)) { - ui->addressLineEdit->setText(RzAddressString(addr)); - addrValid = true; - } else { - ui->addressLineEdit->setText(tr("Invalid Address")); - addrValid = false; - } -} diff --git a/src/dialogs/LinkTypeDialog.h b/src/dialogs/LinkTypeDialog.h deleted file mode 100644 index 4f914805..00000000 --- a/src/dialogs/LinkTypeDialog.h +++ /dev/null @@ -1,66 +0,0 @@ -#ifndef LINKTYPEDIALOG_H -#define LINKTYPEDIALOG_H - -#include "core/Cutter.h" -#include - -namespace Ui { -class LinkTypeDialog; -} - -class LinkTypeDialog : public QDialog -{ - Q_OBJECT - -public: - explicit LinkTypeDialog(QWidget *parent = nullptr); - ~LinkTypeDialog(); - - /** - * @brief Sets the default type which will be displayed in the combo box - * @param type Default type to be used as default type - */ - void setDefaultType(const QString &type); - - /** - * @brief Sets the value of the default address which will be displayed - * If the given address is linked to a type, then it also sets the default - * type to the currently linked type - * @param address The address to be used as default address - * @return true iff the given address string was valid - */ - bool setDefaultAddress(const QString &address); - -private slots: - - /** - * @brief Overrides the done() method of QDialog - * On clicking the Ok button, it links a valid address to a type. - * If "(No Type)" is selected as type, it removes the link. - * In case of an invalid address, it displays error message - * @param r The value which will be returned by exec() - */ - void done(int r) override; - - /** - * @brief Executed whenever the text inside exprLineEdit changes - * If expression evaluates to valid address, it is displayed in addressLineEdit - * Otherwise "Invalid Address" is shown in addressLineEdit - * @param text The current value of exprLineEdit - */ - void on_exprLineEdit_textChanged(const QString &text); - -private: - Ui::LinkTypeDialog *ui; - - bool addrValid; - - /** - * @brief Used for finding the type which is linked to the given address - * @param address - * @return The type linked to "address" if it exists, or empty string otherwise - */ - QString findLinkedType(RVA address); -}; - -#endif // LINKTYPEDIALOG_H diff --git a/src/dialogs/LinkTypeDialog.ui b/src/dialogs/LinkTypeDialog.ui deleted file mode 100644 index 172cc6e9..00000000 --- a/src/dialogs/LinkTypeDialog.ui +++ /dev/null @@ -1,117 +0,0 @@ - - - LinkTypeDialog - - - - 0 - 0 - 500 - 105 - - - - - 500 - 0 - - - - Dialog - - - - - - = - - - - - - - true - - - true - - - - - - - Enter Address - - - - - - - Structure Type - - - structureTypeComboBox - - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - Address/Flag - - - exprLineEdit - - - - - - - - - buttonBox - accepted() - LinkTypeDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - LinkTypeDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - - diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 57c63537..1cc290b7 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -7,7 +7,6 @@ #include "dialogs/EditVariablesDialog.h" #include "dialogs/SetToDataDialog.h" #include "dialogs/EditFunctionDialog.h" -#include "dialogs/LinkTypeDialog.h" #include "dialogs/EditStringDialog.h" #include "dialogs/BreakpointsDialog.h" #include "MainWindow.h" @@ -42,7 +41,6 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *main actionDeleteComment(this), actionDeleteFlag(this), actionDeleteFunction(this), - actionLinkType(this), actionSetBaseBinary(this), actionSetBaseOctal(this), actionSetBaseDecimal(this), @@ -122,10 +120,6 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *main connect(structureOffsetMenu, &QMenu::triggered, this, &DisassemblyContextMenu::on_actionStructureOffsetMenu_triggered); - initAction(&actionLinkType, tr("Link Type to Address"), SLOT(on_actionLinkType_triggered()), - getLinkTypeSequence()); - addAction(&actionLinkType); - addSetAsMenu(); addSeparator(); @@ -667,11 +661,6 @@ QKeySequence DisassemblyContextMenu::getDisplayOptionsSequence() const return {}; // TODO insert correct sequence } -QKeySequence DisassemblyContextMenu::getLinkTypeSequence() const -{ - return { Qt::Key_L }; -} - QList DisassemblyContextMenu::getAddBPSequence() const { return { Qt::Key_F2, Qt::CTRL | Qt::Key_B }; @@ -986,15 +975,6 @@ void DisassemblyContextMenu::on_actionStructureOffsetMenu_triggered(QAction *act Core()->applyStructureOffset(action->data().toString(), offset); } -void DisassemblyContextMenu::on_actionLinkType_triggered() -{ - LinkTypeDialog dialog(mainWindow); - if (!dialog.setDefaultAddress(curHighlightedWord)) { - dialog.setDefaultAddress(RzAddressString(offset)); - } - dialog.exec(); -} - void DisassemblyContextMenu::on_actionDeleteComment_triggered() { Core()->delComment(offset); diff --git a/src/menus/DisassemblyContextMenu.h b/src/menus/DisassemblyContextMenu.h index fe2f40a1..158b1ec7 100644 --- a/src/menus/DisassemblyContextMenu.h +++ b/src/menus/DisassemblyContextMenu.h @@ -74,13 +74,6 @@ private slots: */ void on_actionStructureOffsetMenu_triggered(QAction *action); - /** - * @brief Executed on selecting the "Link Type to Address" option - * Opens the LinkTypeDialog box from where the user can link the address - * to a type - */ - void on_actionLinkType_triggered(); - private: QKeySequence getCopySequence() const; QKeySequence getCommentSequence() const; @@ -99,11 +92,6 @@ private: QKeySequence getEditFunctionSequence() const; QList getAddBPSequence() const; - /** - * @return the shortcut key for "Link Type to Address" option - */ - QKeySequence getLinkTypeSequence() const; - RVA offset; bool canCopy; QString curHighlightedWord; // The current highlighted word @@ -137,8 +125,6 @@ private: QMenu *structureOffsetMenu; - QAction actionLinkType; - QMenu *setBaseMenu; QAction actionSetBaseBinary; QAction actionSetBaseOctal; diff --git a/src/widgets/TypesWidget.cpp b/src/widgets/TypesWidget.cpp index c2e069a6..8e7a0e6e 100644 --- a/src/widgets/TypesWidget.cpp +++ b/src/widgets/TypesWidget.cpp @@ -3,7 +3,6 @@ #include "core/MainWindow.h" #include "common/Helpers.h" #include "dialogs/TypesInteractionDialog.h" -#include "dialogs/LinkTypeDialog.h" #include #include @@ -242,9 +241,6 @@ void TypesWidget::showTypesContextMenu(const QPoint &pt) // Add "Link To Address" option menu.addAction(actionViewType); menu.addAction(actionEditType); - if (t.category == "Struct") { - menu.addAction(ui->actionLink_Type_To_Address); - } } } @@ -338,19 +334,6 @@ void TypesWidget::on_actionDelete_Type_triggered() } } -void TypesWidget::on_actionLink_Type_To_Address_triggered() -{ - LinkTypeDialog dialog(this); - - QModelIndex index = ui->typesTreeView->currentIndex(); - if (index.isValid()) { - TypeDescription t = index.data(TypesModel::TypeDescriptionRole).value(); - dialog.setDefaultType(t.type); - dialog.setDefaultAddress(RzAddressString(Core()->getOffset())); - dialog.exec(); - } -} - void TypesWidget::typeItemDoubleClicked(const QModelIndex &index) { if (!index.isValid()) { diff --git a/src/widgets/TypesWidget.h b/src/widgets/TypesWidget.h index e567a146..dec3ece5 100644 --- a/src/widgets/TypesWidget.h +++ b/src/widgets/TypesWidget.h @@ -105,12 +105,6 @@ private slots: */ void on_actionDelete_Type_triggered(); - /** - * @brief Executed on clicking the Link To Address option in the context menu - * Opens the LinkTypeDialog box from where the user can link a address to a type - */ - void on_actionLink_Type_To_Address_triggered(); - /** * @brief triggers when the user double-clicks an item. This will open * a dialog that shows the Type's content diff --git a/src/widgets/TypesWidget.ui b/src/widgets/TypesWidget.ui index c86b6225..171b8f52 100644 --- a/src/widgets/TypesWidget.ui +++ b/src/widgets/TypesWidget.ui @@ -95,11 +95,6 @@ Delete Type - - - Link Type to Address - - From 4da769a0ae478d859c48840998c161610b53140c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Thu, 23 Sep 2021 20:15:08 +0200 Subject: [PATCH 032/240] Fix Decompiler Copy Shortcut (Fix #2773) (#2778) --- src/menus/DecompilerContextMenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menus/DecompilerContextMenu.cpp b/src/menus/DecompilerContextMenu.cpp index 3216abf3..f6842fea 100644 --- a/src/menus/DecompilerContextMenu.cpp +++ b/src/menus/DecompilerContextMenu.cpp @@ -276,7 +276,7 @@ void DecompilerContextMenu::setActionCopy() // Set all three copy actions &DecompilerContextMenu::actionCopyReferenceAddressTriggered); addAction(&actionCopyReferenceAddress); actionCopyReferenceAddress.setShortcut({ Qt::KeyboardModifier::ControlModifier - | Qt::KeyboardModifier::ControlModifier | Qt::Key_C }); + | Qt::KeyboardModifier::ShiftModifier | Qt::Key_C }); } void DecompilerContextMenu::setActionShowInSubmenu() From 01dc1c23376f9f541b9589f5434ab72b105372b4 Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Fri, 24 Sep 2021 09:25:39 +0200 Subject: [PATCH 033/240] Update rizin submodule to 120235ac6830fac5cc9f9378683056d32a420f5b (#2779) --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index 02417f3d..120235ac 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 02417f3d3f73522a073020cbdecfef52b8c0cb44 +Subproject commit 120235ac6830fac5cc9f9378683056d32a420f5b From 9ddc19fcc6220db3a6ea0e25e9c6a36b6a889a69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 24 Sep 2021 10:16:35 +0200 Subject: [PATCH 034/240] Fix CutterCore::getBinPluginDescriptions() args (#2777) --- src/core/Cutter.cpp | 38 +++++++++++++++------------- src/core/Cutter.h | 2 +- src/dialogs/InitialOptionsDialog.cpp | 2 +- src/dialogs/RizinPluginsDialog.cpp | 2 +- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index a2d81fb7..f95b1d4e 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -2731,28 +2731,32 @@ QStringList CutterCore::getAnalysisPluginNames() return ret; } -QList CutterCore::getRBinPluginDescriptions(const QString &type) +QList CutterCore::getBinPluginDescriptions(bool bin, bool xtr) { CORE_LOCK(); QList ret; RzListIter *it; - RzBinPlugin *bp; - CutterRzListForeach (core->bin->plugins, it, RzBinPlugin, bp) { - RzBinPluginDescription desc; - desc.name = bp->name ? bp->name : ""; - desc.description = bp->desc ? bp->desc : ""; - desc.license = bp->license ? bp->license : ""; - desc.type = "bin"; - ret.append(desc); + if (bin) { + RzBinPlugin *bp; + CutterRzListForeach (core->bin->plugins, it, RzBinPlugin, bp) { + RzBinPluginDescription desc; + desc.name = bp->name ? bp->name : ""; + desc.description = bp->desc ? bp->desc : ""; + desc.license = bp->license ? bp->license : ""; + desc.type = "bin"; + ret.append(desc); + } } - RzBinXtrPlugin *bx; - CutterRzListForeach (core->bin->binxtrs, it, RzBinXtrPlugin, bx) { - RzBinPluginDescription desc; - desc.name = bx->name ? bx->name : ""; - desc.description = bx->desc ? bx->desc : ""; - desc.license = bx->license ? bx->license : ""; - desc.type = "xtr"; - ret.append(desc); + if (xtr) { + RzBinXtrPlugin *bx; + CutterRzListForeach (core->bin->binxtrs, it, RzBinXtrPlugin, bx) { + RzBinPluginDescription desc; + desc.name = bx->name ? bx->name : ""; + desc.description = bx->desc ? bx->desc : ""; + desc.license = bx->license ? bx->license : ""; + desc.type = "xtr"; + ret.append(desc); + } } return ret; } diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 687e71c3..319f54d0 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -534,7 +534,7 @@ public: QStringList getAnalysisPluginNames(); /* Widgets */ - QList getRBinPluginDescriptions(const QString &type = QString()); + QList getBinPluginDescriptions(bool bin = true, bool xtr = true); QList getRIOPluginDescriptions(); QList getRCorePluginDescriptions(); QList getRAsmPluginDescriptions(); diff --git a/src/dialogs/InitialOptionsDialog.cpp b/src/dialogs/InitialOptionsDialog.cpp index 54622656..437e290f 100644 --- a/src/dialogs/InitialOptionsDialog.cpp +++ b/src/dialogs/InitialOptionsDialog.cpp @@ -47,7 +47,7 @@ InitialOptionsDialog::InitialOptionsDialog(MainWindow *main) setTooltipWithConfigHelp(ui->kernelComboBox, "asm.os"); setTooltipWithConfigHelp(ui->bitsComboBox, "asm.bits"); - for (const auto &plugin : core->getRBinPluginDescriptions("bin")) { + for (const auto &plugin : core->getBinPluginDescriptions(true, false)) { ui->formatComboBox->addItem(plugin.name, QVariant::fromValue(plugin)); } diff --git a/src/dialogs/RizinPluginsDialog.cpp b/src/dialogs/RizinPluginsDialog.cpp index cef30200..05bee44f 100644 --- a/src/dialogs/RizinPluginsDialog.cpp +++ b/src/dialogs/RizinPluginsDialog.cpp @@ -10,7 +10,7 @@ RizinPluginsDialog::RizinPluginsDialog(QWidget *parent) { ui->setupUi(this); - for (const auto &plugin : Core()->getRBinPluginDescriptions()) { + for (const auto &plugin : Core()->getBinPluginDescriptions()) { QTreeWidgetItem *item = new QTreeWidgetItem(); item->setText(0, plugin.name); item->setText(1, plugin.description); From 02abe9d13824d63f0b0670a17529505acc82a934 Mon Sep 17 00:00:00 2001 From: Surendrajat Date: Fri, 24 Sep 2021 17:36:19 +0530 Subject: [PATCH 035/240] Update jsdec to development state before it is released (#2749) --- dist/bundle_jsdec.ps1 | 2 +- scripts/jsdec.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/bundle_jsdec.ps1 b/dist/bundle_jsdec.ps1 index a2e1834c..7ab7f8c3 100644 --- a/dist/bundle_jsdec.ps1 +++ b/dist/bundle_jsdec.ps1 @@ -2,7 +2,7 @@ $dist = $args[0] $python = Split-Path((Get-Command python.exe).Path) if (-not (Test-Path -Path 'jsdec' -PathType Container)) { - git clone https://github.com/rizinorg/jsdec.git --branch v0.2.x --depth 1 + git clone https://github.com/rizinorg/jsdec.git --depth 1 } cd jsdec & meson.exe --buildtype=release -Dc_args=-DDUK_USE_DATE_NOW_WINDOWS --prefix=$dist --libdir=lib\plugins --datadir=lib\plugins p build diff --git a/scripts/jsdec.sh b/scripts/jsdec.sh index 95398e24..e0530f09 100755 --- a/scripts/jsdec.sh +++ b/scripts/jsdec.sh @@ -7,7 +7,7 @@ SCRIPTPATH=$(realpath "$(dirname "${BASH_SOURCE[0]}")") cd "$SCRIPTPATH/.." if [[ ! -d jsdec ]]; then - git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch v0.2.x + git clone https://github.com/rizinorg/jsdec.git --depth 1 fi cd jsdec From 3b0df1944acb2c80cfeac2df900d986a0d54b34c Mon Sep 17 00:00:00 2001 From: Surendrajat Date: Fri, 24 Sep 2021 21:50:08 +0530 Subject: [PATCH 036/240] Update jsdec and rz-ghidra to v0.3.0 (#2781) --- dist/CMakeLists.txt | 4 ++-- dist/bundle_jsdec.ps1 | 2 +- scripts/jsdec.sh | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index ade8eee0..5dec4c46 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -109,8 +109,8 @@ if(CUTTER_PACKAGE_RZ_GHIDRA) # installed Cutter. ExternalProject_Add(rz-ghidra GIT_REPOSITORY https://github.com/rizinorg/rz-ghidra - #GIT_TAG v0.2.0 - GIT_TAG c7a50a2e7c0a95cd52b167c9ee0fa1805223f08e + GIT_TAG v0.3.0 + #GIT_TAG c7a50a2e7c0a95cd52b167c9ee0fa1805223f08e #GIT_TAG dev #GIT_SHALLOW ON # disable this line when using commit hash CONFIGURE_COMMAND "" diff --git a/dist/bundle_jsdec.ps1 b/dist/bundle_jsdec.ps1 index 7ab7f8c3..03cbbc75 100644 --- a/dist/bundle_jsdec.ps1 +++ b/dist/bundle_jsdec.ps1 @@ -2,7 +2,7 @@ $dist = $args[0] $python = Split-Path((Get-Command python.exe).Path) if (-not (Test-Path -Path 'jsdec' -PathType Container)) { - git clone https://github.com/rizinorg/jsdec.git --depth 1 + git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch v0.3.0 } cd jsdec & meson.exe --buildtype=release -Dc_args=-DDUK_USE_DATE_NOW_WINDOWS --prefix=$dist --libdir=lib\plugins --datadir=lib\plugins p build diff --git a/scripts/jsdec.sh b/scripts/jsdec.sh index e0530f09..f2954ca1 100755 --- a/scripts/jsdec.sh +++ b/scripts/jsdec.sh @@ -7,7 +7,7 @@ SCRIPTPATH=$(realpath "$(dirname "${BASH_SOURCE[0]}")") cd "$SCRIPTPATH/.." if [[ ! -d jsdec ]]; then - git clone https://github.com/rizinorg/jsdec.git --depth 1 + git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch v0.3.0 fi cd jsdec From 6a4a0b9335f6b5f55679492ca67caf43f5b11e00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 24 Sep 2021 18:23:18 +0200 Subject: [PATCH 037/240] Update Rizin to v0.3.0 --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index 120235ac..be157e86 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 120235ac6830fac5cc9f9378683056d32a420f5b +Subproject commit be157e869c4e71419433dfcbe838dfa8f828c597 From 357c43d60639b3471728f7536fde8a44da7ce54f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 24 Sep 2021 18:23:28 +0200 Subject: [PATCH 038/240] Bump Version to 2.0.3 --- .appveyor.yml | 2 +- CMakeLists.txt | 2 +- docs/source/conf.py | 2 +- src/re.rizin.cutter.appdata.xml | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 6ca0427e..c7421f25 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -version: '2.0-git-{build}' +version: '2.0.3-git-{build}' image: 'Visual Studio 2017' clone_depth: 1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 6571c0eb..b62b8a4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() set(CUTTER_VERSION_MAJOR 2) set(CUTTER_VERSION_MINOR 0) -set(CUTTER_VERSION_PATCH 2) +set(CUTTER_VERSION_PATCH 3) set(CUTTER_VERSION_FULL "${CUTTER_VERSION_MAJOR}.${CUTTER_VERSION_MINOR}.${CUTTER_VERSION_PATCH}") diff --git a/docs/source/conf.py b/docs/source/conf.py index e367779a..8d9d028d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -26,7 +26,7 @@ author = 'The Cutter Developers' # The short X.Y version version = '2.0' # The full version, including a2lpha/beta/rc tags -release = '2.0.2' +release = '2.0.3' # -- General configuration --------------------------------------------------- diff --git a/src/re.rizin.cutter.appdata.xml b/src/re.rizin.cutter.appdata.xml index a3770eae..13ff6101 100644 --- a/src/re.rizin.cutter.appdata.xml +++ b/src/re.rizin.cutter.appdata.xml @@ -25,6 +25,7 @@ xarkes + From 6dab092b515024ba769e81554c91c0d8b9883264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 25 Sep 2021 17:17:49 +0200 Subject: [PATCH 039/240] Join Debug Task on Suspend to avoid races (#2783) --- src/core/Cutter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index f95b1d4e..1fba1124 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -2005,6 +2005,7 @@ void CutterCore::attachDebug(int pid) void CutterCore::suspendDebug() { debugTask->breakTask(); + debugTask->joinTask(); } void CutterCore::stopDebug() From 12df7a001dea64f65222434b5b5a7a94c1d92e06 Mon Sep 17 00:00:00 2001 From: Ezra Steinmetz Date: Sun, 26 Sep 2021 18:05:29 +0300 Subject: [PATCH 040/240] Added documentation on optional Ubuntu packages (#2786) --- docs/source/building.rst | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/docs/source/building.rst b/docs/source/building.rst index 9601b1b1..ed2b61f0 100644 --- a/docs/source/building.rst +++ b/docs/source/building.rst @@ -63,8 +63,20 @@ On Debian-based Linux distributions, all of these essential packages can be inst sudo apt install build-essential cmake meson libzip-dev zlib1g-dev qt5-default libqt5svg5-dev qttools5-dev qttools5-dev-tools +Depending on your configuration you'll might also need the following: + +:: + + # When building with CUTTER_ENABLE_KSYNTAXHIGHLIGHTING (Default) + sudo apt install libkf5syntaxhighlighting-dev + # When building with CUTTER_ENABLE_GRAPHVIZ (Default) + sudo apt install libgraphviz-dev + # when building with CUTTER_ENABLE_PYTHON_BINDINGS + sudo apt install libshiboken2-dev libpyside2-dev qtdeclarative5-dev + + .. note:: - For Ubuntu 18.04 and lower, ``meson`` should be installed with ``pip install --upgrade --user meson``. + For Ubuntu 20.04 and lower (or in any case you get an error ``Meson version is x but project requires >=y``), ``meson`` should be installed with ``pip install --upgrade --user meson``. On Arch-based Linux distributions: From 311cd0307ebb6a93434533e3c664a00f0a395e53 Mon Sep 17 00:00:00 2001 From: Petros S Date: Sat, 9 Oct 2021 19:15:38 +0300 Subject: [PATCH 041/240] Small enhancements in the SdbWidget class. (#2796) * Small enhancements in SdbWidget class. Destructors of child classes should be marked with the `override` keyword. Also since Qt's widgets aren't movable or copyable, we can explicitly let the compiler know with the `Q_DISABLE_COPY_MOVE` macro. * Define Q_DISABLE_COPY_MOVE macro for versions < 5.13.0 in SdbWidget --- src/widgets/SdbWidget.cpp | 2 +- src/widgets/SdbWidget.h | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/widgets/SdbWidget.cpp b/src/widgets/SdbWidget.cpp index 98726e0e..37f3e419 100644 --- a/src/widgets/SdbWidget.cpp +++ b/src/widgets/SdbWidget.cpp @@ -80,7 +80,7 @@ void SdbWidget::on_treeWidget_itemDoubleClicked(QTreeWidgetItem *item, int colum } } -SdbWidget::~SdbWidget() {} +SdbWidget::~SdbWidget() = default; void SdbWidget::on_lockButton_clicked() { diff --git a/src/widgets/SdbWidget.h b/src/widgets/SdbWidget.h index a420d326..42b1457f 100644 --- a/src/widgets/SdbWidget.h +++ b/src/widgets/SdbWidget.h @@ -16,9 +16,25 @@ class SdbWidget : public CutterDockWidget { Q_OBJECT +#if QT_VERSION < QT_VERSION_CHECK(5, 13, 0) +# define Q_DISABLE_COPY(SdbWidget) \ + SdbWidget(const SdbWidget &s) = delete; \ + SdbWidget &operator=(const SdbWidget &s) = delete; + +# define Q_DISABLE_MOVE(SdbWidget) \ + SdbWidget(SdbWidget &&s) = delete; \ + SdbWidget &operator=(SdbWidget &&s) = delete; + +# define Q_DISABLE_COPY_MOVE(SdbWidget) \ + Q_DISABLE_COPY(SdbWidget) \ + Q_DISABLE_MOVE(SdbWidget) +#endif + + Q_DISABLE_COPY_MOVE(SdbWidget) + public: explicit SdbWidget(MainWindow *main); - ~SdbWidget(); + ~SdbWidget() override; private slots: void on_treeWidget_itemDoubleClicked(QTreeWidgetItem *item, int column); From 552cd6dff6f94b0301dd18ddfe8add33b7d75c45 Mon Sep 17 00:00:00 2001 From: Petros S Date: Sat, 9 Oct 2021 19:17:52 +0300 Subject: [PATCH 042/240] Add option to disable the preview when hovering over the assembly (#2795) --- src/common/Configuration.cpp | 10 + src/common/Configuration.h | 3 + src/dialogs/preferences/AsmOptionsWidget.cpp | 10 + src/dialogs/preferences/AsmOptionsWidget.h | 1 + src/dialogs/preferences/AsmOptionsWidget.ui | 233 ++++++++++--------- src/widgets/DisassemblyWidget.cpp | 4 +- 6 files changed, 147 insertions(+), 114 deletions(-) diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 764ecdb5..3c309e83 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -774,6 +774,16 @@ bool Configuration::getOutputRedirectionEnabled() const return outputRedirectEnabled; } +void Configuration::setPreviewValue( bool checked ) +{ + s.setValue("asm.preview", checked); +} + +bool Configuration::getPreviewValue() const +{ + return s.value("asm.preview").toBool(); +} + bool Configuration::getGraphBlockEntryOffset() { return s.value("graphBlockEntryOffset", true).value(); diff --git a/src/common/Configuration.h b/src/common/Configuration.h index f20cbe26..73ed1045 100644 --- a/src/common/Configuration.h +++ b/src/common/Configuration.h @@ -201,6 +201,9 @@ public: void setOutputRedirectionEnabled(bool enabled); bool getOutputRedirectionEnabled() const; + void setPreviewValue(bool checked); + bool getPreviewValue() const; + /** * @brief Recently opened binaries, as shown in NewFileDialog. */ diff --git a/src/dialogs/preferences/AsmOptionsWidget.cpp b/src/dialogs/preferences/AsmOptionsWidget.cpp index 0a67daec..7004b4b4 100644 --- a/src/dialogs/preferences/AsmOptionsWidget.cpp +++ b/src/dialogs/preferences/AsmOptionsWidget.cpp @@ -134,6 +134,10 @@ void AsmOptionsWidget::updateAsmOptionsFromVars() ui->asmTabsOffSpinBox->setValue(Config()->getConfigInt("asm.tabs.off")); ui->asmTabsOffSpinBox->blockSignals(false); + ui->previewCheckBox->blockSignals(true); + ui->previewCheckBox->setChecked(Config()->getPreviewValue()); + ui->previewCheckBox->blockSignals(false); + QList::iterator confCheckbox; // Set the value for each checkbox in "checkboxes" as it exists in the configuration @@ -238,6 +242,12 @@ void AsmOptionsWidget::on_varsubCheckBox_toggled(bool checked) triggerAsmOptionsChanged(); } +void AsmOptionsWidget::on_previewCheckBox_toggled( bool checked ) +{ + Config()->setPreviewValue(checked); + triggerAsmOptionsChanged(); +} + void AsmOptionsWidget::on_buttonBox_clicked(QAbstractButton *button) { switch (ui->buttonBox->buttonRole(button)) { diff --git a/src/dialogs/preferences/AsmOptionsWidget.h b/src/dialogs/preferences/AsmOptionsWidget.h index 0a3d069c..a3ba832e 100644 --- a/src/dialogs/preferences/AsmOptionsWidget.h +++ b/src/dialogs/preferences/AsmOptionsWidget.h @@ -48,6 +48,7 @@ private slots: void on_bytesCheckBox_toggled(bool checked); void on_varsubCheckBox_toggled(bool checked); + void on_previewCheckBox_toggled(bool checked); void on_buttonBox_clicked(QAbstractButton *button); diff --git a/src/dialogs/preferences/AsmOptionsWidget.ui b/src/dialogs/preferences/AsmOptionsWidget.ui index ac629113..e96421a4 100644 --- a/src/dialogs/preferences/AsmOptionsWidget.ui +++ b/src/dialogs/preferences/AsmOptionsWidget.ui @@ -48,8 +48,8 @@ 0 0 - 583 - 668 + 582 + 766 @@ -65,10 +65,34 @@ Disassembly - - + + + + true + + + + + + + 100 + + + 5 + + + + + - Display the bytes of each instruction (asm.bytes) + Align bytes to the left (asm.lbytes) + + + + + + + Show preview when hovering: @@ -82,66 +106,10 @@ - - - - 100 - - - 5 - - - - - + + - Show Disassembly as: - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - true - - - Number of bytes to display (asm.nbytes): - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - Indent disassembly based on reflines depth (asm.indent) - - - - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 10 - - - - - - - - true + Flags (asm.reloff.flags) @@ -171,7 +139,7 @@ - + Tabs before assembly (asm.tabs.off): @@ -181,13 +149,40 @@ - - - - - + + + + true + - Show empty line after every basic block (asm.bb.line) + Number of bytes to display (asm.nbytes): + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Separate bytes with whitespace (asm.bytes.space) + + + + + + + 100 + + + 5 + + + + + + + Display the bytes of each instruction (asm.bytes) @@ -210,44 +205,10 @@ - - + + - Align bytes to the left (asm.lbytes) - - - - - - - Separate bytes with whitespace (asm.bytes.space) - - - - - - - Display flags' real name (asm.flags.real) - - - - - - - Tabs in assembly (asm.tabs): - - - Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse - - - - - - - 100 - - - 5 + Show empty line after every basic block (asm.bb.line) @@ -269,10 +230,56 @@ - - + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 10 + + + + + + - Flags (asm.reloff.flags) + Show Disassembly as: + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Tabs in assembly (asm.tabs): + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + + Indent disassembly based on reflines depth (asm.indent) + + + + + + + Display flags' real name (asm.flags.real) @@ -408,8 +415,8 @@ 0 0 - 581 - 302 + 454 + 286 diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index 32c40e69..95c47375 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -654,7 +654,9 @@ bool DisassemblyWidget::eventFilter(QObject *obj, QEvent *event) jumpToOffsetUnderCursor(cursor); return true; - } else if (event->type() == QEvent::ToolTip && obj == mDisasTextEdit->viewport()) { + } else if (Config()->getPreviewValue() + && event->type() == QEvent::ToolTip + && obj == mDisasTextEdit->viewport()) { QHelpEvent *helpEvent = static_cast(event); auto cursorForWord = mDisasTextEdit->cursorForPosition(helpEvent->pos()); From c205acd77316bb1284245d2823e36fd5f5dd3877 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Sun, 10 Oct 2021 14:51:19 +0200 Subject: [PATCH 043/240] Build jsdec with -Djsc_folder option to embed the javascript code (#2801) --- dist/bundle_jsdec.ps1 | 4 ++-- scripts/jsdec.sh | 4 ++-- src/CutterApplication.cpp | 10 ---------- 3 files changed, 4 insertions(+), 14 deletions(-) diff --git a/dist/bundle_jsdec.ps1 b/dist/bundle_jsdec.ps1 index 03cbbc75..a8e1cd61 100644 --- a/dist/bundle_jsdec.ps1 +++ b/dist/bundle_jsdec.ps1 @@ -2,9 +2,9 @@ $dist = $args[0] $python = Split-Path((Get-Command python.exe).Path) if (-not (Test-Path -Path 'jsdec' -PathType Container)) { - git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch v0.3.0 + git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch v0.3.1 } cd jsdec -& meson.exe --buildtype=release -Dc_args=-DDUK_USE_DATE_NOW_WINDOWS --prefix=$dist --libdir=lib\plugins --datadir=lib\plugins p build +& meson.exe --buildtype=release -Dc_args=-DDUK_USE_DATE_NOW_WINDOWS -Djsc_folder="." -Drizin_plugdir=lib\plugins -prefix=$dist --libdir=lib\plugins --datadir=lib\plugins p build ninja -C build install Remove-Item -Recurse -Force $dist\lib\plugins\core_pdd.lib diff --git a/scripts/jsdec.sh b/scripts/jsdec.sh index f2954ca1..571ecb80 100755 --- a/scripts/jsdec.sh +++ b/scripts/jsdec.sh @@ -7,13 +7,13 @@ SCRIPTPATH=$(realpath "$(dirname "${BASH_SOURCE[0]}")") cd "$SCRIPTPATH/.." if [[ ! -d jsdec ]]; then - git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch v0.3.0 + git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch v0.3.1 fi cd jsdec rm -rf build mkdir build && cd build -meson --buildtype=release --libdir=share/rizin/plugins --datadir=share/rizin/plugins "$@" ../p +meson --buildtype=release -Drizin_plugdir=share/rizin/plugins -Djsc_folder="../" --libdir=share/rizin/plugins --datadir=share/rizin/plugins "$@" ../p ninja ninja install diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index ba06c112..f12539d1 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -184,21 +184,11 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc sleighHome.cd( "share/rizin/plugins/rz_ghidra_sleigh"); // Contents/Resources/rz/share/rizin/plugins/rz_ghidra_sleigh Core()->setConfig("ghidra.sleighhome", sleighHome.absolutePath()); - -# ifdef CUTTER_BUNDLE_JSDEC - auto jsdecHome = rzprefix; - jsdecHome.cd( - "share/rizin/plugins/jsdec"); // Contents/Resources/rz/share/rizin/plugins/jsdec - qputenv("JSDEC_HOME", jsdecHome.absolutePath().toLocal8Bit()); -# endif } #endif #if defined(Q_OS_WIN) && defined(CUTTER_ENABLE_PACKAGING) { -# ifdef CUTTER_BUNDLE_JSDEC - qputenv("JSDEC_HOME", "lib\\plugins\\jsdec"); -# endif auto sleighHome = QDir(QCoreApplication::applicationDirPath()); sleighHome.cd("lib/plugins/rz_ghidra_sleigh"); Core()->setConfig("ghidra.sleighhome", sleighHome.absolutePath()); From 29cce01e1a4b796cd8d79b4eb64dfd0f42bc62df Mon Sep 17 00:00:00 2001 From: Petros S Date: Mon, 11 Oct 2021 08:31:37 +0300 Subject: [PATCH 044/240] =?UTF-8?q?Colorize=20the=20preview=20tooltip=20in?= =?UTF-8?q?=20the=20DisassemblyWidget=20according=20to=20th=E2=80=A6=20(#2?= =?UTF-8?q?799)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/widgets/DisassemblyWidget.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index 95c47375..3e933ccd 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -22,6 +22,8 @@ #include #include +static const int kMaxTooltipWidth = 400; + class DisassemblyTextBlockUserData : public QTextBlockUserData { public: @@ -765,6 +767,14 @@ void DisassemblyWidget::setupColors() mDisasTextEdit->setStyleSheet(QString("QPlainTextEdit { background-color: %1; color: %2; }") .arg(ConfigColor("gui.background").name()) .arg(ConfigColor("btext").name())); + + // Read and set a stylesheet for the QToolTip too + setStyleSheet(QString{"QToolTip { border-width: 1px; max-width: %1px;" + "opacity: 230; background-color: %2;" + "color: %3; border-color: %3;}"} + .arg(kMaxTooltipWidth) + .arg(Config()->getColor("gui.tooltip.background").name()) + .arg(Config()->getColor("gui.tooltip.foreground").name())); } DisassemblyScrollArea::DisassemblyScrollArea(QWidget *parent) : QAbstractScrollArea(parent) {} From ef4a6cf99781099253f3920f61d16cd4db3bca27 Mon Sep 17 00:00:00 2001 From: Surendrajat Date: Fri, 15 Oct 2021 10:04:11 +0530 Subject: [PATCH 045/240] docs: add required pkgs for building cutter on fedora, rhel and centos (#2802) --- docs/source/building.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/source/building.rst b/docs/source/building.rst index ed2b61f0..1e1beb15 100644 --- a/docs/source/building.rst +++ b/docs/source/building.rst @@ -84,6 +84,12 @@ On Arch-based Linux distributions: sudo pacman -Syu --needed base-devel cmake meson qt5-base qt5-svg qt5-tools +On dnf/yum based distributions: + +:: + + sudo dnf install -y gcc gcc-c++ make cmake meson qt5-qtbase-devel qt5-qtsvg-devel qt5-qttools-devel + Building Steps ~~~~~~~~~~~~~~ From af01134ae3e83281f94be8a12e82aef433176ad7 Mon Sep 17 00:00:00 2001 From: AdavisSnakes <57366423+AdavisSnakes@users.noreply.github.com> Date: Sun, 17 Oct 2021 13:02:27 -0400 Subject: [PATCH 046/240] Made BugReporting.cpp output match bug_report.md (#2808) --- src/common/BugReporting.cpp | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/common/BugReporting.cpp b/src/common/BugReporting.cpp index b5ece72e..f2242900 100644 --- a/src/common/BugReporting.cpp +++ b/src/common/BugReporting.cpp @@ -30,16 +30,21 @@ void openIssue() } url = "https://github.com/rizinorg/cutter/issues/new?&body=**Environment information**\n* " "Operating System: " - + osInfo + "\n* Cutter version: " + CUTTER_VERSION_FULL + "\n* File format: " + format - + "\n * Arch: " + arch + "\n * Type: " + type - + "\n\n**Describe the bug**\nA clear and concise description of what the bug " - "is.\n\n**To Reproduce**\n" + + osInfo + "\n* Cutter version: " + CUTTER_VERSION_FULL + "\n* Obtained from:\n" + + " - [x] Built from source\n - [ ] Downloaded release from Cutter website or GitHub " + "\n" + " - [ ] Distribution repository\n* File format: " + + format + "\n * Arch: " + arch + "\n * Type: " + type + + "\n\n**Describe the bug**\n\n" + "\n\n**To Reproduce**\n\n" "Steps to reproduce the behavior:\n1. Go to '...'\n2. Click on '....'\n3. Scroll " "down to '....'\n" - "4. See error\n\n**Expected behavior**\n" - "A clear and concise description of what you expected to happen.\n\n" - "**Screenshots**\nIf applicable, add screenshots to help explain your problem.\n\n" - "**Additional context**\nAdd any other context about the problem here."; + "4. See error\n\n**Expected behavior**\n\n" + "\n\n\n" + "**Screenshots**\n\n\n\n\n" + "**Additional context**\n\n\n"; QDesktopServices::openUrl(QUrl(url, QUrl::TolerantMode)); } From 4ec0a076b462732a2c96b86e255a267cd2ce7b3e Mon Sep 17 00:00:00 2001 From: Dhruv Maroo Date: Sun, 17 Oct 2021 22:37:59 +0530 Subject: [PATCH 047/240] Remove existing string before converting to code (#2803) --- src/core/Cutter.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 1fba1124..82e899ee 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -782,7 +782,9 @@ void CutterCore::editBytesEndian(RVA addr, const QString &bytes) void CutterCore::setToCode(RVA addr) { - cmdRawAt("Cd-", addr); + CORE_LOCK(); + rz_meta_del(core->analysis, RZ_META_TYPE_STRING, core->offset, 1); + rz_meta_del(core->analysis, RZ_META_TYPE_DATA, core->offset, 1); emit instructionChanged(addr); } From e86b7a58c85d045b63ed0afccd84e58fdf474ce5 Mon Sep 17 00:00:00 2001 From: AdavisSnakes <57366423+AdavisSnakes@users.noreply.github.com> Date: Wed, 20 Oct 2021 00:23:59 -0400 Subject: [PATCH 048/240] Added labels above analysis slider (#2809) --- src/dialogs/InitialOptionsDialog.ui | 200 +++++++++++++++++++++++++++- 1 file changed, 195 insertions(+), 5 deletions(-) diff --git a/src/dialogs/InitialOptionsDialog.ui b/src/dialogs/InitialOptionsDialog.ui index 481c409c..e3db9f83 100644 --- a/src/dialogs/InitialOptionsDialog.ui +++ b/src/dialogs/InitialOptionsDialog.ui @@ -115,6 +115,12 @@ + + + 0 + 0 + + 0 @@ -180,6 +186,190 @@ + + + + 0 + + + QLayout::SetDefaultConstraint + + + 0 + + + 0 + + + 0 + + + + + true + + + + 0 + 0 + + + + + 55 + 0 + + + + None + + + + + + + Qt::Horizontal + + + QSizePolicy::Expanding + + + + 40 + 0 + + + + + + + + + 0 + 0 + + + + + 55 + 0 + + + + Auto + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 12 + 0 + + + + + + + + Qt::Horizontal + + + + 40 + 0 + + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 12 + 0 + + + + + + + + + 0 + 0 + + + + + 55 + 0 + + + + Auto Exp + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + + 40 + 0 + + + + + + + + + 0 + 0 + + + + + 55 + 0 + + + + Qt::LeftToRight + + + Advanced + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + @@ -227,8 +417,8 @@ 0 0 - 567 - 418 + 553 + 410 @@ -314,12 +504,12 @@ + + false + Qt::Horizontal - - false - From e96c53aeebb2ca812833e17be03b73f52abd2366 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Mon, 18 Oct 2021 17:03:00 +0800 Subject: [PATCH 049/240] Update Rizin to the latest stable --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index be157e86..5fda9165 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit be157e869c4e71419433dfcbe838dfa8f828c597 +Subproject commit 5fda91650c1665ba06b0b5f9b36d4959e9fb5362 From 0786f49842adf7de827c3d1e377e0ab8e5268af4 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Mon, 18 Oct 2021 17:03:26 +0800 Subject: [PATCH 050/240] Fix computing hashes and entropy of the file --- src/widgets/Dashboard.cpp | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-) diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index 6f547e4b..c641b8b0 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -75,8 +75,9 @@ void Dashboard::updateContents() setBool(this->ui->relocsEdit, item2, "relocs"); // Add file hashes, analysis info and libraries - - QJsonObject hashes = Core()->cmdj("itj").object(); + RzCoreLocked core(Core()); + RzBinFile *bf = rz_bin_cur(core->bin); + RzList *hashes = rz_bin_file_compute_hashes(core->bin, bf, UT64_MAX); // Delete hashesWidget if it isn't null to avoid duplicate components if (hashesWidget) { @@ -90,14 +91,16 @@ void Dashboard::updateContents() ui->hashesVerticalLayout->addWidget(hashesWidget); // Add hashes as a pair of Hash Name : Hash Value. - for (const QString &key : hashes.keys()) { + RzListIter *iter; + RzBinFileHash *hash; + CutterRzListForeach (hashes, iter, RzBinFileHash, hash) { // Create a bold QString with the hash name uppercased - QString label = QString("%1:").arg(key.toUpper()); + QString label = QString("%1:").arg(QString(hash->type).toUpper()); // Define a Read-Only line edit to display the hash value QLineEdit *hashLineEdit = new QLineEdit(); hashLineEdit->setReadOnly(true); - hashLineEdit->setText(hashes.value(key).toString()); + hashLineEdit->setText(hash->hex); // Set cursor position to begining to avoid long hashes (e.g sha256) // to look truncated at the begining @@ -107,23 +110,6 @@ void Dashboard::updateContents() hashesLayout->addRow(new QLabel(label), hashLineEdit); } - // Add the Entropy value of the file to the dashboard - { - // Scope for TempConfig - TempConfig tempConfig; - tempConfig.set("io.va", false); - - // Calculate the Entropy of the entire binary from offset 0 to $s - // where $s is the size of the entire file - QString entropy = Core()->cmdRawAt("ph entropy $s", 0).trimmed(); - - // Define a Read-Only line edit to display the entropy value - QLineEdit *entropyLineEdit = new QLineEdit(); - entropyLineEdit->setReadOnly(true); - entropyLineEdit->setText(entropy); - hashesLayout->addRow(new QLabel(tr("Entropy:")), entropyLineEdit); - } - QJsonObject analinfo = Core()->cmdj("aaij").object(); setPlainText(ui->functionsLineEdit, QString::number(analinfo["fcns"].toInt())); setPlainText(ui->xRefsLineEdit, QString::number(analinfo["xrefs"].toInt())); From e358ff797d4ef3e3b96601baa53b2f3c283d4407 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Thu, 28 Oct 2021 13:48:00 +0800 Subject: [PATCH 051/240] Fix Meson 0.60 build --- cmake/BundledRizin.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index 72455028..a042f807 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -8,7 +8,7 @@ if(WIN32) set(RIZIN_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/$") endif() set(RIZIN_INSTALL_BINPATH ".") - set(MESON_OPTIONS "--prefix=${RIZIN_INSTALL_DIR}" "--bindir=${RIZIN_INSTALL_BINPATH}" "-DRZ_INCDIR=include/librz") + set(MESON_OPTIONS "--prefix=${RIZIN_INSTALL_DIR}" "--bindir=${RIZIN_INSTALL_BINPATH}") else() set(RIZIN_INSTALL_DIR "${CMAKE_CURRENT_BINARY_DIR}/Rizin-prefix") set(MESON_OPTIONS "--prefix=${RIZIN_INSTALL_DIR}" --libdir=lib) From 236f85f83d0d6cf91996e8487a5e251b6aee65e1 Mon Sep 17 00:00:00 2001 From: AdavisSnakes <57366423+AdavisSnakes@users.noreply.github.com> Date: Sat, 6 Nov 2021 05:40:11 -0400 Subject: [PATCH 052/240] Added layout to the attachProcDialog to enable resizing the attach process popup (#2811) --- src/dialogs/AttachProcDialog.ui | 128 +++++++++++++++----------------- 1 file changed, 60 insertions(+), 68 deletions(-) diff --git a/src/dialogs/AttachProcDialog.ui b/src/dialogs/AttachProcDialog.ui index e49e57cb..353043b5 100644 --- a/src/dialogs/AttachProcDialog.ui +++ b/src/dialogs/AttachProcDialog.ui @@ -45,47 +45,43 @@ Processes with same name as currently open file: - - - - 0 - 30 - 794 - 111 - - - - - 0 - 0 - - - - - 16777215 - 16777215 - - - - QTreeView::item + + + + + + 0 + 0 + + + + + 16777215 + 16777215 + + + + QTreeView::item { padding-top: 1px; padding-bottom: 1px; } - - - QFrame::NoFrame - - - 0 - - - 8 - - - true - - + + + QFrame::NoFrame + + + 0 + + + 8 + + + true + + + + @@ -93,41 +89,37 @@ All processes: - - - - 0 - 50 - 794 - 331 - - - - - 16777215 - 16777215 - - - - QTreeView::item + + + + + + 16777215 + 16777215 + + + + QTreeView::item { padding-top: 1px; padding-bottom: 1px; } - - - QFrame::NoFrame - - - 0 - - - 8 - - - true - - + + + QFrame::NoFrame + + + 0 + + + 8 + + + true + + + + From 4061887bfee1b0cd8d5b68197dc5316749732a99 Mon Sep 17 00:00:00 2001 From: AdavisSnakes <57366423+AdavisSnakes@users.noreply.github.com> Date: Sat, 6 Nov 2021 05:41:18 -0400 Subject: [PATCH 053/240] Removed info button globally (#2804) --- src/CutterApplication.cpp | 1 - src/core/MainWindow.cpp | 16 +++++++++++++--- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index f12539d1..2dccd156 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -52,7 +52,6 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc setAttribute(Qt::AA_UseHighDpiPixmaps); // always enabled on Qt >= 6.0.0 #endif setLayoutDirection(Qt::LeftToRight); - // WARN!!! Put initialization code below this line. Code above this line is mandatory to be run // First diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index e7cbe173..7d254031 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -619,7 +619,9 @@ bool MainWindow::openProject(const QString &file) const char *s = rz_project_err_message(err); QString msg = tr("Failed to open project: %1").arg(QString::fromUtf8(s)); RzListIter *it; - CutterRzListForeach(res, it, const char, s) { msg += "\n" + QString::fromUtf8(s); } + CutterRzListForeach (res, it, const char, s) { + msg += "\n" + QString::fromUtf8(s); + } QMessageBox::critical(this, tr("Open Project"), msg); rz_list_free(res); return false; @@ -1134,7 +1136,7 @@ void MainWindow::updateHistoryMenu(QMenu *menu, bool redo) bool history = true; QList actions; - CutterRzListForeach(list, it, RzCoreSeekItem, undo) { + CutterRzListForeach (list, it, RzCoreSeekItem, undo) { RzFlagItem *f = rz_flag_get_at(core->flags, undo->offset, true); char *fname = NULL; if (f) { @@ -1789,8 +1791,16 @@ void MainWindow::mousePressEvent(QMouseEvent *event) } } -bool MainWindow::eventFilter(QObject *, QEvent *event) +bool MainWindow::eventFilter(QObject *obj, QEvent *event) { + // For every create event - disable context help and proceed to next event check + if (event->type() == QEvent::Create) { + if (obj->isWidgetType()) { + auto w = static_cast(obj); + w->setWindowFlags(w->windowFlags() & (~Qt::WindowContextHelpButtonHint)); + } + } + if (event->type() == QEvent::MouseButtonPress) { QMouseEvent *mouseEvent = static_cast(event); if (mouseEvent->button() == Qt::ForwardButton || mouseEvent->button() == Qt::BackButton) { From 896be642ffab4625c16e7af998b397e140bd6c02 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Sat, 13 Nov 2021 21:02:57 +0800 Subject: [PATCH 054/240] Port Sections information to the Rizin API (#2785) --- rizin | 2 +- src/core/Cutter.cpp | 62 ++++++++++++++++++++++++++++++++------------- 2 files changed, 45 insertions(+), 19 deletions(-) diff --git a/rizin b/rizin index 5fda9165..18db8301 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 5fda91650c1665ba06b0b5f9b36d4959e9fb5362 +Subproject commit 18db8301a4cb3b3bc4ab026bcf9b822eb03f86e4 diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 82e899ee..fd0cf0c2 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3121,28 +3121,44 @@ QList CutterCore::getAllSections() CORE_LOCK(); QList sections; - QJsonDocument sectionsDoc = cmdj("iSj entropy"); - QJsonObject sectionsObj = sectionsDoc.object(); - QJsonArray sectionsArray = sectionsObj[RJsonKey::sections].toArray(); + RzBinObject *o = rz_bin_cur_object(core->bin); + if (!o) { + return sections; + } - for (const QJsonValue &value : sectionsArray) { - QJsonObject sectionObject = value.toObject(); - - QString name = sectionObject[RJsonKey::name].toString(); - if (name.isEmpty()) + RzList *sects = rz_bin_object_get_sections(o); + if (!sects) { + return sections; + } + RzList *hashnames = rz_list_newf(free); + if (!hashnames) { + return sections; + } + rz_list_push(hashnames, rz_str_new("entropy")); + RzListIter *it; + RzBinSection *sect; + CutterRzListForeach (sects, it, RzBinSection, sect) { + if (RZ_STR_ISEMPTY(sect->name)) continue; SectionDescription section; - section.name = name; - section.vaddr = sectionObject[RJsonKey::vaddr].toVariant().toULongLong(); - section.vsize = sectionObject[RJsonKey::vsize].toVariant().toULongLong(); - section.paddr = sectionObject[RJsonKey::paddr].toVariant().toULongLong(); - section.size = sectionObject[RJsonKey::size].toVariant().toULongLong(); - section.perm = sectionObject[RJsonKey::perm].toString(); - section.entropy = sectionObject[RJsonKey::entropy].toString(); + section.name = sect->name; + section.vaddr = sect->vaddr; + section.vsize = sect->vsize; + section.paddr = sect->paddr; + section.size = sect->size; + section.perm = rz_str_rwx_i(sect->perm); + HtPP *digests = rz_core_bin_section_digests(core, sect, hashnames); + if (!digests) { + continue; + } + const char *entropy = (const char*)ht_pp_find(digests, "entropy", NULL); + section.entropy = rz_str_get(entropy); + ht_pp_free(digests); sections << section; } + rz_list_free(sects); return sections; } @@ -3151,9 +3167,19 @@ QStringList CutterCore::getSectionList() CORE_LOCK(); QStringList ret; - QJsonArray sectionsArray = cmdj("iSj").array(); - for (const QJsonValue &value : sectionsArray) { - ret << value.toObject()[RJsonKey::name].toString(); + RzBinObject *o = rz_bin_cur_object(core->bin); + if (!o) { + return ret; + } + + RzList *sects = rz_bin_object_get_sections(o); + if (!sects) { + return ret; + } + RzListIter *it; + RzBinSection *sect; + CutterRzListForeach (sects, it, RzBinSection, sect) { + ret << sect->name; } return ret; } From c07ce55581b14ed141b42f99f932eb712d541cf3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 15 Nov 2021 15:36:26 +0100 Subject: [PATCH 055/240] Fix stderr/stdin confusion and avoid crash on fdopen --- src/widgets/ConsoleWidget.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/widgets/ConsoleWidget.cpp b/src/widgets/ConsoleWidget.cpp index 92638534..db378068 100644 --- a/src/widgets/ConsoleWidget.cpp +++ b/src/widgets/ConsoleWidget.cpp @@ -424,7 +424,9 @@ void ConsoleWidget::processQueuedOutput() while (pipeSocket->canReadLine()) { QString output = QString(pipeSocket->readLine()); - fprintf(origStderr, "%s", output.toStdString().c_str()); + if (origStderr) { + fprintf(origStderr, "%s", output.toStdString().c_str()); + } // Get the last segment that wasn't overwritten by carriage return output = output.trimmed(); @@ -449,7 +451,7 @@ void ConsoleWidget::redirectOutput() pipeSocket = new QLocalSocket(this); - origStdin = fdopen(dup(fileno(stderr)), "r"); + origStdin = fdopen(dup(fileno(stdin)), "r"); origStderr = fdopen(dup(fileno(stderr)), "a"); origStdout = fdopen(dup(fileno(stdout)), "a"); #ifdef Q_OS_WIN From bd4342c4cbbe200381ccae0cd1abe56c983ab4a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 15 Nov 2021 15:36:55 +0100 Subject: [PATCH 056/240] Fix VisualNavbar Crash on Haiku --- src/widgets/VisualNavbar.cpp | 8 ++++++++ src/widgets/VisualNavbar.h | 1 + 2 files changed, 9 insertions(+) diff --git a/src/widgets/VisualNavbar.cpp b/src/widgets/VisualNavbar.cpp index 1f125b26..3ff9f2ac 100644 --- a/src/widgets/VisualNavbar.cpp +++ b/src/widgets/VisualNavbar.cpp @@ -25,6 +25,8 @@ VisualNavbar::VisualNavbar(MainWindow *main, QWidget *parent) { Q_UNUSED(parent); + blockTooltip = false; + setObjectName("visualNavbar"); setWindowTitle(tr("Visual navigation bar")); // setMovable(false); @@ -240,11 +242,17 @@ void VisualNavbar::on_seekChanged(RVA addr) void VisualNavbar::mousePressEvent(QMouseEvent *event) { + if (blockTooltip) { + return; + } qreal x = qhelpers::mouseEventPos(event).x(); RVA address = localXToAddress(x); if (address != RVA_INVALID) { auto tooltipPos = qhelpers::mouseEventGlobalPos(event); + blockTooltip = true; // on Haiku, the below call sometimes triggers another mouseMoveEvent, + // causing infinite recursion QToolTip::showText(tooltipPos, toolTipForAddress(address), this, this->rect()); + blockTooltip = false; if (event->buttons() & Qt::LeftButton) { event->accept(); Core()->seek(address); diff --git a/src/widgets/VisualNavbar.h b/src/widgets/VisualNavbar.h index 195c23a1..b11eb170 100644 --- a/src/widgets/VisualNavbar.h +++ b/src/widgets/VisualNavbar.h @@ -48,6 +48,7 @@ private: unsigned int previousWidth = 0; QList xToAddress; + bool blockTooltip; RVA localXToAddress(double x); double addressToLocalX(RVA address); From 5179ec5d842e6937fdf98985cc468728d1cad72f Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Thu, 18 Nov 2021 01:14:01 +0800 Subject: [PATCH 057/240] Update Rizin to 0.3.1 --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index 18db8301..6ef55aa6 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 18db8301a4cb3b3bc4ab026bcf9b822eb03f86e4 +Subproject commit 6ef55aa63a563864774f4777dcd1a69933b62a72 From 8bab611c7fae0c45bc98098bb196f400e4caeec7 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Thu, 18 Nov 2021 01:16:12 +0800 Subject: [PATCH 058/240] Bump version to 2.0.4 --- .appveyor.yml | 2 +- CMakeLists.txt | 2 +- docs/source/conf.py | 2 +- src/re.rizin.cutter.appdata.xml | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index c7421f25..5dc483e0 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -version: '2.0.3-git-{build}' +version: '2.0.4-git-{build}' image: 'Visual Studio 2017' clone_depth: 1 diff --git a/CMakeLists.txt b/CMakeLists.txt index b62b8a4e..4c878fd8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() set(CUTTER_VERSION_MAJOR 2) set(CUTTER_VERSION_MINOR 0) -set(CUTTER_VERSION_PATCH 3) +set(CUTTER_VERSION_PATCH 4) set(CUTTER_VERSION_FULL "${CUTTER_VERSION_MAJOR}.${CUTTER_VERSION_MINOR}.${CUTTER_VERSION_PATCH}") diff --git a/docs/source/conf.py b/docs/source/conf.py index 8d9d028d..f366fc03 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -26,7 +26,7 @@ author = 'The Cutter Developers' # The short X.Y version version = '2.0' # The full version, including a2lpha/beta/rc tags -release = '2.0.3' +release = '2.0.4' # -- General configuration --------------------------------------------------- diff --git a/src/re.rizin.cutter.appdata.xml b/src/re.rizin.cutter.appdata.xml index 13ff6101..ccff7dd2 100644 --- a/src/re.rizin.cutter.appdata.xml +++ b/src/re.rizin.cutter.appdata.xml @@ -25,6 +25,7 @@ xarkes + From 78a9a112099e0d045773d77f4b1166fc3b7d2eef Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Tue, 23 Nov 2021 19:25:20 +0100 Subject: [PATCH 059/240] Fix jsdec build on windows (#2840) --- dist/bundle_jsdec.ps1 | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/dist/bundle_jsdec.ps1 b/dist/bundle_jsdec.ps1 index a8e1cd61..fe3ded97 100644 --- a/dist/bundle_jsdec.ps1 +++ b/dist/bundle_jsdec.ps1 @@ -5,6 +5,12 @@ if (-not (Test-Path -Path 'jsdec' -PathType Container)) { git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch v0.3.1 } cd jsdec -& meson.exe --buildtype=release -Dc_args=-DDUK_USE_DATE_NOW_WINDOWS -Djsc_folder="." -Drizin_plugdir=lib\plugins -prefix=$dist --libdir=lib\plugins --datadir=lib\plugins p build +& meson.exe --buildtype=release -Dc_args=-DDUK_USE_DATE_NOW_WINDOWS -Djsc_folder=".." -Drizin_plugdir=lib\plugins --prefix=$dist --libdir=lib\plugins --datadir=lib\plugins p build ninja -C build install +$ErrorActionPreference = 'Stop' +$pathdll = "$dist\lib\plugins\core_pdd.dll" +if(![System.IO.File]::Exists($pathdll)) { + type build\meson-logs\meson-log.txt + throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll)) +} Remove-Item -Recurse -Force $dist\lib\plugins\core_pdd.lib From 6438cc4d5089024b29449345251ae366b0e8c7e3 Mon Sep 17 00:00:00 2001 From: Anton Angelov Date: Wed, 1 Dec 2021 05:11:29 -0800 Subject: [PATCH 060/240] Update analysis method handling for name/realname (#2843) This also fixes a crash when adding a new class method. --- src/core/Cutter.cpp | 7 +++-- src/core/CutterDescriptions.h | 1 + src/dialogs/EditMethodDialog.cpp | 47 ++++++++++++++++++++++++++++++-- src/dialogs/EditMethodDialog.h | 3 ++ src/dialogs/EditMethodDialog.ui | 46 ++++++++++++++++++++++++++----- src/widgets/ClassesWidget.cpp | 12 ++++++-- src/widgets/ClassesWidget.h | 10 ++++++- 7 files changed, 112 insertions(+), 14 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index fd0cf0c2..89729ac6 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3152,7 +3152,7 @@ QList CutterCore::getAllSections() if (!digests) { continue; } - const char *entropy = (const char*)ht_pp_find(digests, "entropy", NULL); + const char *entropy = (const char *)ht_pp_find(digests, "entropy", NULL); section.entropy = rz_str_get(entropy); ht_pp_free(digests); @@ -3376,6 +3376,7 @@ QList CutterCore::getAnalysisClassMethods(const QStri { AnalysisMethodDescription desc; desc.name = QString::fromUtf8(meth->name); + desc.realName = QString::fromUtf8(meth->real_name); desc.addr = meth->addr; desc.vtableOffset = meth->vtable_offset; ret.append(desc); @@ -3465,6 +3466,7 @@ bool CutterCore::getAnalysisMethod(const QString &cls, const QString &meth, return false; } desc->name = QString::fromUtf8(analysisMeth.name); + desc->realName = QString::fromUtf8(analysisMeth.real_name); desc->addr = analysisMeth.addr; desc->vtableOffset = analysisMeth.vtable_offset; rz_analysis_class_method_fini(&analysisMeth); @@ -3475,7 +3477,8 @@ void CutterCore::setAnalysisMethod(const QString &className, const AnalysisMetho { CORE_LOCK(); RzAnalysisMethod analysisMeth; - analysisMeth.name = strdup(meth.name.toUtf8().constData()); + analysisMeth.name = rz_str_new(meth.name.toUtf8().constData()); + analysisMeth.real_name = rz_str_new(meth.realName.toUtf8().constData()); analysisMeth.addr = meth.addr; analysisMeth.vtable_offset = meth.vtableOffset; rz_analysis_class_method_set(core->analysis, className.toUtf8().constData(), &analysisMeth); diff --git a/src/core/CutterDescriptions.h b/src/core/CutterDescriptions.h index 2fbaeac8..941be488 100644 --- a/src/core/CutterDescriptions.h +++ b/src/core/CutterDescriptions.h @@ -248,6 +248,7 @@ struct BinClassDescription struct AnalysisMethodDescription { QString name; + QString realName; RVA addr; st64 vtableOffset; }; diff --git a/src/dialogs/EditMethodDialog.cpp b/src/dialogs/EditMethodDialog.cpp index 28914f80..c9e9fdfc 100644 --- a/src/dialogs/EditMethodDialog.cpp +++ b/src/dialogs/EditMethodDialog.cpp @@ -26,6 +26,9 @@ EditMethodDialog::EditMethodDialog(bool classFixed, QWidget *parent) connect(ui->virtualCheckBox, &QCheckBox::stateChanged, this, &EditMethodDialog::updateVirtualUI); connect(ui->nameEdit, &QLineEdit::textChanged, this, &EditMethodDialog::validateInput); + connect(ui->realNameEdit, &QLineEdit::textChanged, this, &EditMethodDialog::updateName); + connect(ui->autoRenameCheckBox, &QCheckBox::stateChanged, this, + &EditMethodDialog::updateAutoRenameEnabled); } EditMethodDialog::~EditMethodDialog() {} @@ -54,15 +57,42 @@ void EditMethodDialog::validateInput() } } +void EditMethodDialog::updateName() +{ + if (ui->autoRenameCheckBox->isChecked()) { + ui->nameEdit->setText(convertRealNameToName(ui->realNameEdit->text())); + } + + validateInput(); +} + +void EditMethodDialog::updateAutoRenameEnabled() +{ + ui->nameEdit->setEnabled(!ui->autoRenameCheckBox->isChecked()); + + if (ui->autoRenameCheckBox->isChecked()) { + ui->nameEdit->setText(convertRealNameToName(ui->realNameEdit->text())); + } +} + bool EditMethodDialog::inputValid() { - if (ui->nameEdit->text().isEmpty()) { + if (ui->nameEdit->text().isEmpty() || ui->realNameEdit->text().isEmpty()) { return false; } // TODO: do more checks here, for example for name clashes return true; } +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()); +} + void EditMethodDialog::setClass(const QString &className) { if (classComboBox) { @@ -89,6 +119,7 @@ void EditMethodDialog::setClass(const QString &className) void EditMethodDialog::setMethod(const AnalysisMethodDescription &desc) { ui->nameEdit->setText(desc.name); + ui->realNameEdit->setText(desc.realName); ui->addressEdit->setText(desc.addr != RVA_INVALID ? RzAddressString(desc.addr) : nullptr); if (desc.vtableOffset >= 0) { @@ -99,6 +130,16 @@ void EditMethodDialog::setMethod(const AnalysisMethodDescription &desc) ui->vtableOffsetEdit->setText(nullptr); } + // Check if auto-rename should be enabled + bool enableAutoRename = ui->nameEdit->text().isEmpty() + || ui->nameEdit->text() == convertRealNameToName(ui->realNameEdit->text()); + ui->autoRenameCheckBox->setChecked(enableAutoRename); + + // Set focus to real name edit widget if auto-rename is enabled + if (enableAutoRename) { + ui->realNameEdit->setFocus(); + } + updateVirtualUI(); validateInput(); } @@ -120,6 +161,7 @@ AnalysisMethodDescription EditMethodDialog::getMethod() const { AnalysisMethodDescription ret; ret.name = ui->nameEdit->text(); + ret.realName = ui->realNameEdit->text(); ret.addr = Core()->num(ui->addressEdit->text()); if (!ui->virtualCheckBox->isChecked()) { ret.vtableOffset = -1; @@ -145,7 +187,8 @@ bool EditMethodDialog::showDialog(const QString &title, bool classFixed, QString void EditMethodDialog::newMethod(QString className, const QString &meth, QWidget *parent) { AnalysisMethodDescription desc; - desc.name = meth; + desc.name = convertRealNameToName(meth); + desc.realName = meth; desc.vtableOffset = -1; desc.addr = Core()->getOffset(); diff --git a/src/dialogs/EditMethodDialog.h b/src/dialogs/EditMethodDialog.h index df414977..1f388b89 100644 --- a/src/dialogs/EditMethodDialog.h +++ b/src/dialogs/EditMethodDialog.h @@ -59,6 +59,8 @@ private slots: void updateVirtualUI(); void validateInput(); + void updateName(); + void updateAutoRenameEnabled(); private: std::unique_ptr ui; @@ -72,6 +74,7 @@ private: QString fixedClass; bool inputValid(); + static QString convertRealNameToName(const QString& realName); }; #endif // EDITMETHODDIALOG_H diff --git a/src/dialogs/EditMethodDialog.ui b/src/dialogs/EditMethodDialog.ui index effc6608..b9237c46 100644 --- a/src/dialogs/EditMethodDialog.ui +++ b/src/dialogs/EditMethodDialog.ui @@ -29,45 +29,69 @@ - Name: + Unique Identifier (name): - + + + + + + + + Auto-Rename + + + false + + + + + + + Display Name (realname): + + + + + + + Address: - + - + Virtual: - + - + Offset in VTable: - + @@ -84,6 +108,14 @@ + + nameEdit + autoRenameCheckBox + realNameEdit + addressEdit + virtualCheckBox + vtableOffsetEdit + diff --git a/src/widgets/ClassesWidget.cpp b/src/widgets/ClassesWidget.cpp index 9185ce03..42c461ad 100644 --- a/src/widgets/ClassesWidget.cpp +++ b/src/widgets/ClassesWidget.cpp @@ -17,6 +17,8 @@ QVariant ClassesModel::headerData(int section, Qt::Orientation, int role) const switch (section) { case NAME: return tr("Name"); + case REAL_NAME: + return tr("Real Name"); case TYPE: return tr("Type"); case OFFSET: @@ -188,7 +190,8 @@ QVariant BinClassesModel::data(const QModelIndex &index, int role) const case OFFSET: return cls->addr == RVA_INVALID ? QString() : RzAddressString(cls->addr); case VTABLE: - return cls->vtableAddr == RVA_INVALID ? QString() : RzAddressString(cls->vtableAddr); + return cls->vtableAddr == RVA_INVALID ? QString() + : RzAddressString(cls->vtableAddr); default: return QVariant(); } @@ -312,7 +315,8 @@ void AnalysisClassesModel::classAttrsChanged(const QString &cls) layoutChanged({ persistentIndex }); } -const QVector &AnalysisClassesModel::getAttrs(const QString &cls) const +const QVector & +AnalysisClassesModel::getAttrs(const QString &cls) const { auto it = attrs->find(cls); if (it != attrs->end()) { @@ -454,6 +458,8 @@ QVariant AnalysisClassesModel::data(const QModelIndex &index, int role) const switch (index.column()) { case NAME: return meth.name; + case REAL_NAME: + return meth.realName; case TYPE: return tr("method"); case OFFSET: @@ -476,6 +482,8 @@ QVariant AnalysisClassesModel::data(const QModelIndex &index, int role) const return QVariant::fromValue(meth.addr); case NameRole: return meth.name; + case RealNameRole: + return meth.realName; case TypeRole: return QVariant::fromValue(RowType::Method); default: diff --git a/src/widgets/ClassesWidget.h b/src/widgets/ClassesWidget.h index cbd3fcad..bfe9034e 100644 --- a/src/widgets/ClassesWidget.h +++ b/src/widgets/ClassesWidget.h @@ -24,7 +24,7 @@ class ClassesWidget; class ClassesModel : public QAbstractItemModel { public: - enum Columns { NAME = 0, TYPE, OFFSET, VTABLE, COUNT }; + enum Columns { NAME = 0, REAL_NAME, TYPE, OFFSET, VTABLE, COUNT }; /** * @brief values for TypeRole data @@ -61,6 +61,14 @@ public: */ static const int VTableRole = Qt::UserRole + 3; + /** + * @brief Real Name role of data for QModelIndex + * + * will contain values of QString, used for sorting, + * as well as identifying classes and methods + */ + static const int RealNameRole = Qt::UserRole + 4; + explicit ClassesModel(QObject *parent = nullptr) : QAbstractItemModel(parent) {} QVariant headerData(int section, Qt::Orientation orientation, From d85383fcfcdca82591facbe4fc4fd1eee72cbda1 Mon Sep 17 00:00:00 2001 From: Petros S Date: Sun, 5 Dec 2021 10:53:45 +0200 Subject: [PATCH 061/240] Support for previewing in the Graph widget (#2797) Common functionality has been moved to the DisassemblyPreview namespace. --- src/CMakeLists.txt | 1 + src/common/Configuration.h | 11 +++ src/common/DisassemblyPreview.cpp | 84 +++++++++++++++++++ src/common/DisassemblyPreview.h | 38 +++++++++ .../preferences/GraphOptionsWidget.cpp | 7 ++ src/dialogs/preferences/GraphOptionsWidget.h | 1 + src/dialogs/preferences/GraphOptionsWidget.ui | 7 ++ src/widgets/DisassemblerGraphView.cpp | 56 +++++++++++++ src/widgets/DisassemblerGraphView.h | 4 + src/widgets/DisassemblyWidget.cpp | 28 +------ 10 files changed, 211 insertions(+), 26 deletions(-) create mode 100644 src/common/DisassemblyPreview.cpp create mode 100644 src/common/DisassemblyPreview.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 651af4bb..8aae0d5d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -8,6 +8,7 @@ set(SOURCES dialogs/WriteCommandsDialogs.cpp widgets/DisassemblerGraphView.cpp widgets/OverviewView.cpp + common/DisassemblyPreview.cpp common/RichTextPainter.cpp dialogs/InitialOptionsDialog.cpp dialogs/AboutDialog.cpp diff --git a/src/common/Configuration.h b/src/common/Configuration.h index 73ed1045..3343e271 100644 --- a/src/common/Configuration.h +++ b/src/common/Configuration.h @@ -167,6 +167,17 @@ public: void setGraphMinFontSize(int sz) { s.setValue("graph.minfontsize", sz); } + /** + * @brief Get the boolean setting for preview in Graph + * @return True if preview checkbox is checked, false otherwise + */ + bool getGraphPreview() { return s.value("graph.preview").toBool(); } + /** + * @brief Set the boolean setting for preview in Graph + * @param checked is a boolean that represents the preview checkbox + */ + void setGraphPreview(bool checked) { s.setValue("graph.preview", checked); } + /** * @brief Getters and setters for the transaparent option state and scale factor for bitmap * graph exports. diff --git a/src/common/DisassemblyPreview.cpp b/src/common/DisassemblyPreview.cpp new file mode 100644 index 00000000..df6fb58b --- /dev/null +++ b/src/common/DisassemblyPreview.cpp @@ -0,0 +1,84 @@ +#include "DisassemblyPreview.h" +#include "Configuration.h" +#include "widgets/GraphView.h" + +#include +#include +#include +#include + +DisassemblyTextBlockUserData::DisassemblyTextBlockUserData(const DisassemblyLine &line) + : line { line } +{ +} + +DisassemblyTextBlockUserData *getUserData(const QTextBlock &block) +{ + QTextBlockUserData *userData = block.userData(); + if (!userData) { + return nullptr; + } + + return static_cast(userData); +} + +QString DisassemblyPreview::getToolTipStyleSheet() +{ + return QString { "QToolTip { border-width: 1px; max-width: %1px;" + "opacity: 230; background-color: %2;" + "color: %3; border-color: %3;}" } + .arg(400) + .arg(Config()->getColor("gui.tooltip.background").name()) + .arg(Config()->getColor("gui.tooltip.foreground").name()); +} + +bool DisassemblyPreview::showDisasPreview(QWidget *parent, const QPoint &pointOfEvent, + const RVA offsetFrom) +{ + QProcessEnvironment env; + QPoint point = pointOfEvent; + + QList refs = Core()->getXRefs(offsetFrom, false, false); + if (refs.length()) { + if (refs.length() > 1) { + qWarning() << QObject::tr( + "More than one (%1) references here. Weird behaviour expected.") + .arg(refs.length()); + } + + RVA offsetTo = refs.at(0).to; // This is the offset we want to preview + + if (Q_UNLIKELY(offsetFrom != refs.at(0).from)) { + qWarning() << QObject::tr("offsetFrom (%1) differs from refs.at(0).from (%(2))") + .arg(offsetFrom) + .arg(refs.at(0).from); + } + + /* + * Only if the offset we point *to* is different from the one the cursor is currently + * on *and* the former is a valid offset, we are allowed to get a preview of offsetTo + */ + if (offsetTo != offsetFrom && offsetTo != RVA_INVALID) { + QStringList disasmPreview = Core()->getDisassemblyPreview(offsetTo, 10); + + // Last check to make sure the returned preview isn't an empty text (QStringList) + if (!disasmPreview.isEmpty()) { + const QFont &fnt = Config()->getFont(); + + QFontMetrics fm { fnt }; + + QString tooltip = + QString { "
Disassembly Preview:
%3
" } + .arg(fnt.family()) + .arg(qMax(8, fnt.pointSize() - 1)) + .arg(disasmPreview.join("
")); + + QToolTip::showText(point, tooltip, parent, QRect {}, 3500); + return true; + } + } + } + return false; +} diff --git a/src/common/DisassemblyPreview.h b/src/common/DisassemblyPreview.h new file mode 100644 index 00000000..656b818e --- /dev/null +++ b/src/common/DisassemblyPreview.h @@ -0,0 +1,38 @@ +#ifndef DISASSEMBLYPREVIEW_H +#define DISASSEMBLYPREVIEW_H + +#include + +#include "core/CutterDescriptions.h" + +class QWidget; + +class DisassemblyTextBlockUserData : public QTextBlockUserData +{ +public: + DisassemblyLine line; + + explicit DisassemblyTextBlockUserData(const DisassemblyLine &line); +}; + +DisassemblyTextBlockUserData *getUserData(const QTextBlock &block); + +/** + * @brief Namespace to define relevant functions + * + * @ingroup DisassemblyPreview + */ +namespace DisassemblyPreview { +/*! + * @brief Get the QString that defines the stylesheet for tooltip + * @return A QString for the stylesheet + */ +QString getToolTipStyleSheet(); + +/*! + * @brief Show a QToolTip that previews the disassembly that is pointed to + * @return True if the tooltip is shown + */ +bool showDisasPreview(QWidget *parent, const QPoint &pointOfEvent, const RVA offsetFrom); +} +#endif diff --git a/src/dialogs/preferences/GraphOptionsWidget.cpp b/src/dialogs/preferences/GraphOptionsWidget.cpp index e3980d09..7a896174 100644 --- a/src/dialogs/preferences/GraphOptionsWidget.cpp +++ b/src/dialogs/preferences/GraphOptionsWidget.cpp @@ -15,6 +15,7 @@ GraphOptionsWidget::GraphOptionsWidget(PreferencesDialog *dialog) ui->setupUi(this); ui->checkTransparent->setChecked(Config()->getBitmapTransparentState()); ui->blockEntryCheckBox->setChecked(Config()->getGraphBlockEntryOffset()); + ui->graphPreviewCheckBox->setChecked(Config()->getGraphPreview()); ui->bitmapGraphScale->setValue(Config()->getBitmapExportScaleFactor() * 100.0); updateOptionsFromVars(); @@ -84,6 +85,12 @@ void GraphOptionsWidget::on_graphOffsetCheckBox_toggled(bool checked) triggerOptionsChanged(); } +void GraphOptionsWidget::on_graphPreviewCheckBox_toggled( bool checked ) +{ + Config()->setGraphPreview(checked); + triggerOptionsChanged(); +} + void GraphOptionsWidget::checkTransparentStateChanged(int checked) { Config()->setBitmapTransparentState(checked); diff --git a/src/dialogs/preferences/GraphOptionsWidget.h b/src/dialogs/preferences/GraphOptionsWidget.h index 7b69dd19..e69c9bb1 100644 --- a/src/dialogs/preferences/GraphOptionsWidget.h +++ b/src/dialogs/preferences/GraphOptionsWidget.h @@ -33,6 +33,7 @@ private slots: void on_maxColsSpinBox_valueChanged(int value); void on_minFontSizeSpinBox_valueChanged(int value); void on_graphOffsetCheckBox_toggled(bool checked); + void on_graphPreviewCheckBox_toggled(bool checked); void checkTransparentStateChanged(int checked); void bitmapGraphScaleValueChanged(double value); diff --git a/src/dialogs/preferences/GraphOptionsWidget.ui b/src/dialogs/preferences/GraphOptionsWidget.ui index d4fbca05..7d9c8c5e 100644 --- a/src/dialogs/preferences/GraphOptionsWidget.ui +++ b/src/dialogs/preferences/GraphOptionsWidget.ui @@ -42,6 +42,13 @@ + + + + Show preview when hovering (graph.preview) + + + diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index 9df66ac4..7f434ff6 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -5,6 +5,7 @@ #include "core/MainWindow.h" #include "common/Colors.h" #include "common/Configuration.h" +#include "common/DisassemblyPreview.h" #include "common/TempConfig.h" #include "common/SyntaxHighlighter.h" #include "common/BasicBlockHighlighter.h" @@ -41,7 +42,12 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable *se { highlight_token = nullptr; auto *layout = new QVBoxLayout(this); + setTooltipStylesheet(); + // Signals that require a refresh all + connect(Config(), &Configuration::colorsUpdated, this, + &DisassemblerGraphView::setTooltipStylesheet); + connect(Core(), &CutterCore::refreshAll, this, &DisassemblerGraphView::refreshView); connect(Core(), &CutterCore::commentsChanged, this, &DisassemblerGraphView::refreshView); connect(Core(), &CutterCore::functionRenamed, this, &DisassemblerGraphView::refreshView); @@ -140,6 +146,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable *se layout->setAlignment(Qt::AlignTop); this->scale_thickness_multiplier = true; + installEventFilter(this); } void DisassemblerGraphView::connectSeekChanged(bool disconn) @@ -524,6 +531,40 @@ GraphView::EdgeConfiguration DisassemblerGraphView::edgeConfiguration(GraphView: return ec; } +bool DisassemblerGraphView::eventFilter(QObject *obj, QEvent *event) +{ + if (event->type() == QEvent::Type::ToolTip && Config()->getGraphPreview()) { + + QHelpEvent *helpEvent = static_cast(event); + QPoint pointOfEvent = helpEvent->globalPos(); + QPoint point = viewToLogicalCoordinates(helpEvent->pos()); + + GraphBlock *block = getBlockContaining(point); + + if (block == nullptr) { + return false; + } + + // offsetFrom is the address which on top the cursor triggered this + RVA offsetFrom = RVA_INVALID; + + /* + * getAddrForMouseEvent() doesn't work for jmps, like + * getInstrForMouseEvent() with false as a 3rd argument. + */ + Instr *inst = getInstrForMouseEvent(*block, &point, true); + if (inst != nullptr) { + offsetFrom = inst->addr; + } + + // Don't preview anything for a small scale + if (getViewScale() >= 0.8) { + return DisassemblyPreview::showDisasPreview(this, pointOfEvent, offsetFrom); + } + } + return CutterGraphView::eventFilter(obj, event); +} + RVA DisassemblerGraphView::getAddrForMouseEvent(GraphBlock &block, QPoint *point) { DisassemblyBlock &db = disassembly_blocks[block.entry]; @@ -702,6 +743,11 @@ void DisassemblerGraphView::takeFalse() } } +void DisassemblerGraphView::setTooltipStylesheet() +{ + setStyleSheet(DisassemblyPreview::getToolTipStyleSheet()); +} + void DisassemblerGraphView::seekInstruction(bool previous_instr) { RVA addr = seekable->getOffset(); @@ -951,3 +997,13 @@ bool DisassemblerGraphView::Instr::contains(ut64 addr) const { return this->addr <= addr && (addr - this->addr) < size; } + +RVA DisassemblerGraphView::readDisassemblyOffset(QTextCursor tc) +{ + auto userData = getUserData(tc.block()); + if (!userData) { + return RVA_INVALID; + } + + return userData->line.offset; +} diff --git a/src/widgets/DisassemblerGraphView.h b/src/widgets/DisassemblerGraphView.h index beb2b209..07bfc9ed 100644 --- a/src/widgets/DisassemblerGraphView.h +++ b/src/widgets/DisassemblerGraphView.h @@ -139,10 +139,13 @@ protected: QPoint pos) override; void contextMenuEvent(QContextMenuEvent *event) override; void restoreCurrentBlock() override; + bool eventFilter(QObject *obj, QEvent *event) override; + private slots: void showExportDialog() override; void onActionHighlightBITriggered(); void onActionUnhighlightBITriggered(); + void setTooltipStylesheet(); private: bool transition_dont_seek = false; @@ -175,6 +178,7 @@ private: DisassemblyBlock *blockForAddress(RVA addr); void seekLocal(RVA addr, bool update_viewport = true); void seekInstruction(bool previous_instr); + RVA readDisassemblyOffset(QTextCursor tc); CutterSeekable *seekable = nullptr; QList shortcuts; diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index 3e933ccd..97c83e64 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -1,6 +1,7 @@ #include "DisassemblyWidget.h" #include "menus/DisassemblyContextMenu.h" #include "common/Configuration.h" +#include "common/DisassemblyPreview.h" #include "common/Helpers.h" #include "common/TempConfig.h" #include "common/SelectionHighlight.h" @@ -22,26 +23,6 @@ #include #include -static const int kMaxTooltipWidth = 400; - -class DisassemblyTextBlockUserData : public QTextBlockUserData -{ -public: - DisassemblyLine line; - - explicit DisassemblyTextBlockUserData(const DisassemblyLine &line) { this->line = line; } -}; - -static DisassemblyTextBlockUserData *getUserData(const QTextBlock &block) -{ - QTextBlockUserData *userData = block.userData(); - if (!userData) { - return nullptr; - } - - return static_cast(userData); -} - DisassemblyWidget::DisassemblyWidget(MainWindow *main) : MemoryDockWidget(MemoryWidgetType::Disassembly, main), mCtxMenu(new DisassemblyContextMenu(this, main)), @@ -769,12 +750,7 @@ void DisassemblyWidget::setupColors() .arg(ConfigColor("btext").name())); // Read and set a stylesheet for the QToolTip too - setStyleSheet(QString{"QToolTip { border-width: 1px; max-width: %1px;" - "opacity: 230; background-color: %2;" - "color: %3; border-color: %3;}"} - .arg(kMaxTooltipWidth) - .arg(Config()->getColor("gui.tooltip.background").name()) - .arg(Config()->getColor("gui.tooltip.foreground").name())); + setStyleSheet(DisassemblyPreview::getToolTipStyleSheet()); } DisassemblyScrollArea::DisassemblyScrollArea(QWidget *parent) : QAbstractScrollArea(parent) {} From 8cc4d14a6fe0b1a0ce6baf2a2f280342eed64e0c Mon Sep 17 00:00:00 2001 From: billow Date: Sun, 19 Dec 2021 18:00:45 +0800 Subject: [PATCH 062/240] Use Rizin API for Comments and Instruction writing (#2856) --- src/core/Cutter.cpp | 17 +++++++++++------ src/core/Cutter.h | 14 ++++++++++++-- src/dialogs/CommentsDialog.cpp | 18 ++++++++---------- src/menus/DecompilerContextMenu.cpp | 2 +- src/menus/DisassemblyContextMenu.cpp | 2 +- 5 files changed, 33 insertions(+), 20 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 89729ac6..92cf4acb 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -392,7 +392,7 @@ bool CutterCore::isRedirectableDebugee() RzIODesc *desc; CutterRzListForeach (descs, it, RzIODesc, desc) { QString URI = QString(desc->uri); - if (URI.contains("ptrace") | URI.contains("mach")) { + if (URI.contains("ptrace") || URI.contains("mach")) { return true; } } @@ -747,19 +747,22 @@ QString CutterCore::getInstructionOpcode(RVA addr) void CutterCore::editInstruction(RVA addr, const QString &inst) { - cmdRawAt(QString("wa %1").arg(inst), addr); + CORE_LOCK(); + rz_core_write_assembly(core, addr, inst.trimmed().toStdString().c_str(), false, false); emit instructionChanged(addr); } void CutterCore::nopInstruction(RVA addr) { - cmdRawAt("wao nop", addr); + CORE_LOCK(); + applyAtSeek([&]() { rz_core_hack(core, "nop"); }, addr); emit instructionChanged(addr); } void CutterCore::jmpReverse(RVA addr) { - cmdRawAt("wao recj", addr); + CORE_LOCK(); + applyAtSeek([&]() { rz_core_hack(core, "recj"); }, addr); emit instructionChanged(addr); } @@ -849,13 +852,15 @@ int CutterCore::sizeofDataMeta(RVA addr) void CutterCore::setComment(RVA addr, const QString &cmt) { - cmdRawAt(QString("CCu base64:%1").arg(QString(cmt.toLocal8Bit().toBase64())), addr); + CORE_LOCK(); + rz_meta_set_string(core->analysis, RZ_META_TYPE_COMMENT, addr, cmt.toStdString().c_str()); emit commentsChanged(addr); } void CutterCore::delComment(RVA addr) { - cmdRawAt("CC-", addr); + CORE_LOCK(); + rz_meta_del(core->analysis, RZ_META_TYPE_COMMENT, addr, 1); emit commentsChanged(addr); } diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 319f54d0..fbd73b6e 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -15,6 +15,7 @@ #include #include #include +#include class AsyncTaskManager; class BasicInstructionHighlighter; @@ -115,6 +116,14 @@ public: return cmdRawAt(str.toUtf8().constData(), address); } + void applyAtSeek(std::function fn, RVA address) + { + RVA oldOffset = getOffset(); + seekSilent(address); + fn(); + seekSilent(oldOffset); + } + QJsonDocument cmdj(const char *str); QJsonDocument cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); } QJsonDocument cmdjAt(const char *str, RVA address); @@ -267,9 +276,10 @@ public: void createNewClass(const QString &cls); void renameClass(const QString &oldName, const QString &newName); void deleteClass(const QString &cls); - bool getAnalysisMethod(const QString &cls, const QString &meth, AnalysisMethodDescription *desc); + bool getAnalysisMethod(const QString &cls, const QString &meth, + AnalysisMethodDescription *desc); void renameAnalysisMethod(const QString &className, const QString &oldMethodName, - const QString &newMethodName); + const QString &newMethodName); void setAnalysisMethod(const QString &cls, const AnalysisMethodDescription &meth); /* File related methods */ diff --git a/src/dialogs/CommentsDialog.cpp b/src/dialogs/CommentsDialog.cpp index 7a7117ba..f5cc1544 100644 --- a/src/dialogs/CommentsDialog.cpp +++ b/src/dialogs/CommentsDialog.cpp @@ -34,20 +34,18 @@ void CommentsDialog::setComment(const QString &comment) void CommentsDialog::addOrEditComment(RVA offset, QWidget *parent) { - QString oldComment = Core()->cmdRawAt("CC.", offset); - // Remove newline at the end added by cmd - oldComment.remove(oldComment.length() - 1, 1); - CommentsDialog c(parent); + QString comment = Core()->getCommentAt(offset); + CommentsDialog dialog(parent); - if (oldComment.isNull() || oldComment.isEmpty()) { - c.setWindowTitle(tr("Add Comment at %1").arg(RzAddressString(offset))); + if (comment.isNull() || comment.isEmpty()) { + dialog.setWindowTitle(tr("Add Comment at %1").arg(RzAddressString(offset))); } else { - c.setWindowTitle(tr("Edit Comment at %1").arg(RzAddressString(offset))); + dialog.setWindowTitle(tr("Edit Comment at %1").arg(RzAddressString(offset))); } - c.setComment(oldComment); - if (c.exec()) { - QString comment = c.getComment(); + dialog.setComment(comment); + if (dialog.exec()) { + comment = dialog.getComment(); if (comment.isEmpty()) { Core()->delComment(offset); } else { diff --git a/src/menus/DecompilerContextMenu.cpp b/src/menus/DecompilerContextMenu.cpp index f6842fea..e0e1baff 100644 --- a/src/menus/DecompilerContextMenu.cpp +++ b/src/menus/DecompilerContextMenu.cpp @@ -154,7 +154,7 @@ void DecompilerContextMenu::aboutToShowSlot() { if (this->firstOffsetInLine != RVA_MAX) { actionShowInSubmenu.setVisible(true); - QString comment = Core()->cmdRawAt("CC.", this->firstOffsetInLine); + QString comment = Core()->getCommentAt(firstOffsetInLine); actionAddComment.setVisible(true); if (comment.isEmpty()) { actionDeleteComment.setVisible(false); diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 1cc290b7..420d15bc 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -536,7 +536,7 @@ void DisassemblyContextMenu::aboutToShowSlot() QString stringDefinition = Core()->cmdRawAt("Cs.", offset); actionSetAsStringRemove.setVisible(!stringDefinition.isEmpty()); - QString comment = Core()->cmdRawAt("CC.", offset); + QString comment = Core()->getCommentAt(offset); if (comment.isNull() || comment.isEmpty()) { actionDeleteComment.setVisible(false); From 9de1d56c93d0352783d991f44a0a8cd9e9a44fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Tue, 21 Dec 2021 13:39:25 +0100 Subject: [PATCH 063/240] Update references for dev/stable split --- .appveyor.yml | 3 ++- .github/workflows/ccpp.yml | 6 ++++-- .github/workflows/docs.yml | 2 +- .github/workflows/linter.yml | 6 ++++-- CONTRIBUTING.md | 2 +- README.md | 6 +++--- docs/source/building.rst | 2 +- docs/source/contributing/code/development-guidelines.rst | 2 +- docs/source/contributing/code/release-procedure.rst | 9 ++++----- docs/source/contributing/docs/getting-started.rst | 2 +- src/re.rizin.cutter.appdata.xml | 2 +- 11 files changed, 23 insertions(+), 19 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 5dc483e0..9d0bf2f5 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -80,7 +80,8 @@ for: - branches: only: - - master + - dev + - stable - skip_non_tags: true diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 3ab3426b..789e1def 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -3,14 +3,16 @@ name: Cutter CI on: push: branches: - - master + - dev + - stable tags: - v* - upload-test* pull_request: branches: - - master + - dev + - stable jobs: build: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 41645177..a423c001 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -3,7 +3,7 @@ name: Docs on: push: branches: - - master + - dev jobs: deploy: diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index 3f516b2e..dfe70b68 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -3,10 +3,12 @@ name: "Linter" on: push: branches: - - master + - dev + - stable pull_request: branches: - - master + - dev + - stable jobs: changes: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 61f1ecf9..cf9ebb07 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ Please follow our contribution guidelines: https://cutter.re/docs/contributing.h ## Contributing to the documentation -The documentation is something important for newcomers. As of today the documentation can be found [here](https://cutter.re/docs/) and it stands in the [docs](https://github.com/rizinorg/cutter/tree/master/docs) folder. +The documentation is something important for newcomers. As of today the documentation can be found [here](https://cutter.re/docs/) and it stands in the [docs](docs) folder. The API Reference is automatically generated from the source code, so it is strongly advised to document your code. Check issues marked as "Documentation" on our issues [list](https://github.com/rizinorg/cutter/issues?q=is%3Aissue+is%3Aopen+label%3ADocumentation). diff --git a/README.md b/README.md index 5c1e71ee..4962b466 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,14 @@ -Cutter logo +Cutter logo # Cutter Cutter is a free and open-source reverse engineering platform powered by [rizin](https://github.com/rizinorg/rizin). It aims at being an advanced and customizable reverse engineering platform while keeping the user experience in mind. Cutter is created by reverse engineers for reverse engineers. [![Cutter CI](https://github.com/rizinorg/cutter/workflows/Cutter%20CI/badge.svg)](https://github.com/rizinorg/cutter/actions?query=workflow%3A%22Cutter+CI%22) -[![Build status](https://ci.appveyor.com/api/projects/status/tn7kttv55b8wf799/branch/master?svg=true)](https://ci.appveyor.com/project/rizinorg/cutter/branch/master) +[![Build status](https://ci.appveyor.com/api/projects/status/tn7kttv55b8wf799/branch/dev?svg=true)](https://ci.appveyor.com/project/rizinorg/cutter/branch/dev) [![Total alerts](https://img.shields.io/lgtm/alerts/g/rizinorg/cutter.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/rizinorg/cutter/alerts/) -![Screenshot](https://raw.githubusercontent.com/rizinorg/cutter/master/docs/source/images/screenshot.png) +![Screenshot](https://raw.githubusercontent.com/rizinorg/cutter/dev/docs/source/images/screenshot.png) ## Learn more at [cutter.re](https://cutter.re). diff --git a/docs/source/building.rst b/docs/source/building.rst index 1e1beb15..5f2d9c0a 100644 --- a/docs/source/building.rst +++ b/docs/source/building.rst @@ -6,7 +6,7 @@ Building If you just want to use the latest Release version of Cutter, please note that we provide pre-compiled binaries for Windows, Linux, and macOS on our `release page `_ and - `CI page `_ for latest development builds. + `CI page `_ for latest development builds. This page describes how to do a basic build from the command line. If you are planning to modify Cutter it is recommended to also read our :doc:`development environment setup`. diff --git a/docs/source/contributing/code/development-guidelines.rst b/docs/source/contributing/code/development-guidelines.rst index 919978ca..948d134f 100644 --- a/docs/source/contributing/code/development-guidelines.rst +++ b/docs/source/contributing/code/development-guidelines.rst @@ -257,7 +257,7 @@ In order to update one submodule individually, use the following code: .. code:: sh cd rizin - git checkout master && git pull + git checkout dev && git pull cd .. git add rizin git commit -m "Update rizin submodule" diff --git a/docs/source/contributing/code/release-procedure.rst b/docs/source/contributing/code/release-procedure.rst index bd416931..0b66147d 100644 --- a/docs/source/contributing/code/release-procedure.rst +++ b/docs/source/contributing/code/release-procedure.rst @@ -4,7 +4,7 @@ Release Procedure 1. Update translations submodule ``_ 1. The latest archive from Crowdin should already be in the repository, if not make sure to merge any automated Pull Request from Crowdin (e.g. https://github.com/rizinorg/cutter-translations/pull/9) 2. Update submodule in cutter -2. If there is a desire to keep working in the master branch, create branch for the release and do all the following work there. +2. Merge the current state of dev into stable. This can happen even earlier in order to feature-freeze the release while keeping development on dev alive. The rizin submodule on stable should point to a commit of stable in rizin and dev to a commit in dev. 3. Lock rzghidra and rzdec versions downloaded by packaging scripts. Specify a tag or commit hash. 4. Update version #. appveyor.yml @@ -19,11 +19,11 @@ Release Procedure 6. Create a GitHub release, mark it as pre-release save draft, set the tag to v1.11.0-rc1 7. Wait for packages to build 8. On all operating systems do the `Basic testing procedure`_ to ensure nothing badly broken. -9. If any major problems are found, open an issue and fix them. If a release branch is used fix them in master and cherry pick into release branch. If the amount of changes is sufficiently large repeat from step 3. increasing rc number by one. +9. If any major problems are found, open an issue and fix them in dev and cherry pick into release branch. If the amount of changes is sufficiently large repeat from step 3. increasing rc number by one. 10. Update version to 1.11.0 11. Create tag 12. Create release - * Fill the release notes in the Release description. Preparing release notes can begin earlier. Compare current master or release branch against previous release to find all the changes. Choose the most important ones. Don't duplicate the commit log. Release notes should be a summary for people who don't want to read whole commit log. Group related changes together under titles such as "New features", "Bug Fixes", "Decompiler", "Rizin" and similar. + * Fill the release notes in the Release description. Preparing release notes can begin earlier. Compare current dev branch against previous release to find all the changes. Choose the most important ones. Don't duplicate the commit log. Release notes should be a summary for people who don't want to read whole commit log. Group related changes together under titles such as "New features", "Bug Fixes", "Decompiler", "Rizin" and similar. 13. Prepare announcement tweets and messages to send in the Telegram group, reddit, and others. 14. Close milestone if there was one @@ -33,8 +33,7 @@ Bugfix Release -------------- The process for bugfix release is similar no normal release procedure described above with some differences. -* Create the branch from the last tag instead of master or reuse the branch from x.y.0 release if it was already created. -* Cherry pick required bugfixes from master into the branch. +* Cherry pick required bugfixes from dev into the stable. * Increase the third version number x.y.n into x.y.(n+1) . diff --git a/docs/source/contributing/docs/getting-started.rst b/docs/source/contributing/docs/getting-started.rst index f624edda..edc07493 100644 --- a/docs/source/contributing/docs/getting-started.rst +++ b/docs/source/contributing/docs/getting-started.rst @@ -16,7 +16,7 @@ How can you help? The following sections suggest ways you can contribute to Cutter's documentation. The list isn't complete as the possibilities are limitless. -The source for this documentation is available in the `docs directory `_ on Cutter's repository. This source can be generated according to the steps described in the :ref:`building docs page`. When the docs are updated, they are generated and pushed directly to the website at . The source for the website and blog are available on the `cutter.re's repository `_ and are served from the ``gh-pages`` branch. +The source for this documentation is available in the `docs directory `_ on Cutter's repository. This source can be generated according to the steps described in the :ref:`building docs page`. When the docs are updated, they are generated and pushed directly to the website at . The source for the website and blog are available on the `cutter.re's repository `_ and are served from the ``gh-pages`` branch. .. tip:: Document what you wished to see. If you are a user of Cutter, try to think what things you would want to see documented when you started using the project. Sometimes, the best contributions are coming from your own needs. diff --git a/src/re.rizin.cutter.appdata.xml b/src/re.rizin.cutter.appdata.xml index ccff7dd2..cfec367e 100644 --- a/src/re.rizin.cutter.appdata.xml +++ b/src/re.rizin.cutter.appdata.xml @@ -16,7 +16,7 @@ - https://raw.githubusercontent.com/rizinorg/cutter/master/docs/source/images/screenshot.png + https://raw.githubusercontent.com/rizinorg/cutter/stable/docs/source/images/screenshot.png Main UI From 009c8dffb4fb85929afba3216746744a77adc3ba Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Wed, 22 Dec 2021 09:57:58 +0100 Subject: [PATCH 064/240] Update Rizin to dev and use CMake config files (#2855) API usage has been adjusted. There are now also cmake config files directly installed by Rizin itself, so we don't need to keep a custom FindRizin.cmake file in Cutter. This remove that file and just uses `find_package(Rizin COMPONENTS Core)`, which will use the cmake files installed on the system. --- CMakeLists.txt | 4 +- cmake/BundledRizin.cmake | 4 +- cmake/FindRizin.cmake | 117 ------------------------------ dist/CMakeLists.txt | 8 +- dist/MacOSSetupBundle.cmake.in | 1 - dist/bundle_jsdec.ps1 | 4 +- rizin | 2 +- scripts/jsdec.sh | 4 +- src/common/ColorThemeWorker.cpp | 9 ++- src/common/Configuration.cpp | 2 +- src/core/Cutter.cpp | 25 ++++--- src/dialogs/BreakpointsDialog.cpp | 12 +-- src/widgets/BreakpointWidget.cpp | 6 +- 13 files changed, 41 insertions(+), 157 deletions(-) delete mode 100644 cmake/FindRizin.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index 4c878fd8..bfdc7e6c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -48,8 +48,8 @@ if(CUTTER_USE_BUNDLED_RIZIN) include(BundledRizin) set(RIZIN_TARGET Rizin) else() - find_package(Rizin REQUIRED) - set(RIZIN_TARGET Rizin::librz) + find_package(Rizin COMPONENTS Core REQUIRED) + set(RIZIN_TARGET Rizin::Core) endif() set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index a042f807..ba6813e3 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -47,8 +47,8 @@ else() endif() set (RZ_LIBS rz_core rz_config rz_cons rz_io rz_util rz_flag rz_asm rz_debug - rz_hash rz_bin rz_lang rz_io rz_analysis rz_parse rz_bp rz_egg rz_reg - rz_search rz_syscall rz_socket rz_magic rz_crypto rz_type rz_diff) + rz_hash rz_bin rz_lang rz_il rz_analysis rz_parse rz_bp rz_egg rz_reg + rz_search rz_syscall rz_socket rz_magic rz_crypto rz_type rz_diff rz_sign) set (RZ_EXTRA_LIBS rz_main) set (RZ_BIN rz-agent rz-bin rizin rz-diff rz-find rz-gg rz-hash rz-run rz-asm rz-ax) diff --git a/cmake/FindRizin.cmake b/cmake/FindRizin.cmake deleted file mode 100644 index 924e112a..00000000 --- a/cmake/FindRizin.cmake +++ /dev/null @@ -1,117 +0,0 @@ -# - Find Rizin (librz) -# -# This module provides the following imported targets, if found: -# -# Rizin::librz -# -# This will define the following variables: -# (but don't use them if you don't know what you are doing, use Rizin::librz) -# -# Rizin_FOUND - True if librz has been found. -# Rizin_INCLUDE_DIRS - librz include directory -# Rizin_LIBRARIES - List of libraries when using librz. -# Rizin_LIBRARY_DIRS - librz library directories -# -# If librz was found using find_library and not pkg-config, the following variables will also be set: -# Rizin_LIBRARY_ - Path to library rz_ - -if(WIN32) - find_path(Rizin_INCLUDE_DIRS - NAMES rz_core.h rz_bin.h rz_util.h - HINTS - "$ENV{HOME}/bin/prefix/rizin/include/librz" - /usr/local/include/libr - /usr/include/librz) - find_path(SDB_INCLUDE_DIR - NAMES sdb.h sdbht.h sdb_version.h - HINTS - "$ENV{HOME}/bin/prefix/rizin/include/librz/sdb" - /usr/local/include/librz/sdb - /usr/include/librz/sdb) - - list(APPEND Rizin_INCLUDE_DIRS ${SDB_INCLUDE_DIR}) - - set(Rizin_LIBRARY_NAMES - core - config - cons - io - util - flag - asm - debug - hash - bin - lang - io - analysis - parse - bp - egg - reg - search - syscall - socket - magic - crypto - type) - - set(Rizin_LIBRARIES "") - set(Rizin_LIBRARIES_VARS "") - foreach(libname ${Rizin_LIBRARY_NAMES}) - find_library(Rizin_LIBRARY_${libname} - rz_${libname} - HINTS - "$ENV{HOME}/bin/prefix/rizin/lib" - /usr/local/lib - /usr/lib) - - list(APPEND Rizin_LIBRARIES ${Rizin_LIBRARY_${libname}}) - list(APPEND Rizin_LIBRARIES_VARS "Rizin_LIBRARY_${libname}") - endforeach() - - set(Rizin_LIBRARY_DIRS "") - - add_library(Rizin::librz UNKNOWN IMPORTED) - set_target_properties(Rizin::librz PROPERTIES - IMPORTED_LOCATION "${Rizin_LIBRARY_core}" - IMPORTED_LINK_INTERFACE_LIBRARIES "${Rizin_LIBRARIES}" - INTERFACE_LINK_DIRECTORIES "${Rizin_LIBRARY_DIRS}" - INTERFACE_INCLUDE_DIRECTORIES "${Rizin_INCLUDE_DIRS}") - set(Rizin_TARGET Rizin::librz) -else() - # support installation locations used by rizin scripts like sys/user.sh and sys/install.sh - if(CUTTER_USE_ADDITIONAL_RIZIN_PATHS) - set(Rizin_CMAKE_PREFIX_PATH_TEMP ${CMAKE_PREFIX_PATH}) - list(APPEND CMAKE_PREFIX_PATH "$ENV{HOME}/bin/prefix/rizin") # sys/user.sh - list(APPEND CMAKE_PREFIX_PATH "/usr/local") # sys/install.sh - endif() - - find_package(PkgConfig REQUIRED) - if(CMAKE_VERSION VERSION_LESS "3.6") - pkg_search_module(Rizin REQUIRED rz_core) - else() - pkg_search_module(Rizin IMPORTED_TARGET REQUIRED rz_core) - endif() - - # reset CMAKE_PREFIX_PATH - if(CUTTER_USE_ADDITIONAL_RIZIN_PATHS) - set(CMAKE_PREFIX_PATH ${Rizin_CMAKE_PREFIX_PATH_TEMP}) - endif() - - if((TARGET PkgConfig::Rizin) AND (NOT CMAKE_VERSION VERSION_LESS "3.11.0")) - set_target_properties(PkgConfig::Rizin PROPERTIES IMPORTED_GLOBAL ON) - add_library(Rizin::librz ALIAS PkgConfig::Rizin) - set(Rizin_TARGET Rizin::librz) - elseif(Rizin_FOUND) - add_library(Rizin::librz INTERFACE IMPORTED) - set_target_properties(Rizin::librz PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${Rizin_INCLUDE_DIRS}") - set_target_properties(Rizin::librz PROPERTIES - INTERFACE_LINK_LIBRARIES "${Rizin_LIBRARIES}") - set(Rizin_TARGET Rizin::librz) - endif() -endif() - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Rizin REQUIRED_VARS Rizin_TARGET Rizin_LIBRARIES Rizin_INCLUDE_DIRS) diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index 5dec4c46..cf57cc66 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -84,9 +84,7 @@ if(APPLE) if (CUTTER_PACKAGE_JSDEC AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) install(CODE " - execute_process(COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/jsdec.sh\" --prefix=\${CMAKE_INSTALL_PREFIX} - \"-Drizin_incdir=\${CMAKE_INSTALL_PREFIX}/include/librz\" - \"-Drizin_libdir=\${CMAKE_INSTALL_PREFIX}/lib\" + execute_process(COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/jsdec.sh\" --pkg-config-path=\${CMAKE_INSTALL_PREFIX}/lib/pkgconfig --prefix=\${CMAKE_INSTALL_PREFIX} WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE SCRIPT_RESULT) if (SCRIPT_RESULT) @@ -109,9 +107,9 @@ if(CUTTER_PACKAGE_RZ_GHIDRA) # installed Cutter. ExternalProject_Add(rz-ghidra GIT_REPOSITORY https://github.com/rizinorg/rz-ghidra - GIT_TAG v0.3.0 + #GIT_TAG v0.3.0 #GIT_TAG c7a50a2e7c0a95cd52b167c9ee0fa1805223f08e - #GIT_TAG dev + GIT_TAG dev #GIT_SHALLOW ON # disable this line when using commit hash CONFIGURE_COMMAND "" BUILD_COMMAND "" diff --git a/dist/MacOSSetupBundle.cmake.in b/dist/MacOSSetupBundle.cmake.in index 3666bae7..88bd6fd8 100644 --- a/dist/MacOSSetupBundle.cmake.in +++ b/dist/MacOSSetupBundle.cmake.in @@ -25,7 +25,6 @@ file(COPY "${INFO_PLIST_PATH}" DESTINATION "${BUNDLE_PATH}/Contents") # replace absolute path from build directory in rizin pkgconfig files with relative ones file(GLOB RZ_PCFILES "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig/rz_*.pc") -list(APPEND RZ_PCFILES "${CMAKE_INSTALL_PREFIX}/lib/pkgconfig/librz.pc") foreach (_pcfile ${RZ_PCFILES}) file(READ "${_pcfile}" _text) string(REGEX REPLACE "^prefix=[^\n]*\n" "prefix=\${pcfiledir}/../..\n" _text "${_text}") diff --git a/dist/bundle_jsdec.ps1 b/dist/bundle_jsdec.ps1 index fe3ded97..762d7b11 100644 --- a/dist/bundle_jsdec.ps1 +++ b/dist/bundle_jsdec.ps1 @@ -2,10 +2,10 @@ $dist = $args[0] $python = Split-Path((Get-Command python.exe).Path) if (-not (Test-Path -Path 'jsdec' -PathType Container)) { - git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch v0.3.1 + git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch master } cd jsdec -& meson.exe --buildtype=release -Dc_args=-DDUK_USE_DATE_NOW_WINDOWS -Djsc_folder=".." -Drizin_plugdir=lib\plugins --prefix=$dist --libdir=lib\plugins --datadir=lib\plugins p build +& meson.exe --buildtype=release -Dc_args=-DDUK_USE_DATE_NOW_WINDOWS -Djsc_folder=".." --prefix=$dist p build ninja -C build install $ErrorActionPreference = 'Stop' $pathdll = "$dist\lib\plugins\core_pdd.dll" diff --git a/rizin b/rizin index 6ef55aa6..0e87fbd8 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 6ef55aa63a563864774f4777dcd1a69933b62a72 +Subproject commit 0e87fbd8107dfe463924b498c84687cfc5fe2b7f diff --git a/scripts/jsdec.sh b/scripts/jsdec.sh index 571ecb80..caee0759 100755 --- a/scripts/jsdec.sh +++ b/scripts/jsdec.sh @@ -7,13 +7,13 @@ SCRIPTPATH=$(realpath "$(dirname "${BASH_SOURCE[0]}")") cd "$SCRIPTPATH/.." if [[ ! -d jsdec ]]; then - git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch v0.3.1 + git clone https://github.com/rizinorg/jsdec.git --depth 2 --branch master fi cd jsdec rm -rf build mkdir build && cd build -meson --buildtype=release -Drizin_plugdir=share/rizin/plugins -Djsc_folder="../" --libdir=share/rizin/plugins --datadir=share/rizin/plugins "$@" ../p +meson --buildtype=release -Djsc_folder="../" "$@" ../p ninja ninja install diff --git a/src/common/ColorThemeWorker.cpp b/src/common/ColorThemeWorker.cpp index 34851920..a7ca2bc8 100644 --- a/src/common/ColorThemeWorker.cpp +++ b/src/common/ColorThemeWorker.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "common/Configuration.h" @@ -29,7 +30,7 @@ const QStringList ColorThemeWorker::rizinUnusedOptions = { ColorThemeWorker::ColorThemeWorker(QObject *parent) : QObject(parent) { - char *szThemes = rz_str_home(RZ_HOME_THEMES); + char *szThemes = rz_path_home_prefix(RZ_THEMES); customRzThemesLocationPath = szThemes; rz_mem_free(szThemes); if (!QDir(customRzThemesLocationPath).exists()) { @@ -37,7 +38,7 @@ ColorThemeWorker::ColorThemeWorker(QObject *parent) : QObject(parent) } QDir currDir { - QStringLiteral("%1%2%3").arg(rz_sys_prefix(nullptr)).arg(RZ_SYS_DIR).arg(RZ_THEMES) + QStringLiteral("%1%2%3").arg(rz_path_prefix(nullptr)).arg(RZ_SYS_DIR).arg(RZ_THEMES) }; if (currDir.exists()) { standardRzThemesLocationPath = currDir.absolutePath(); @@ -132,9 +133,9 @@ QJsonDocument ColorThemeWorker::getTheme(const QString &themeName) const if (themeName != curr) { RzCoreLocked core(Core()); - rz_core_load_theme(core, themeName.toUtf8().constData()); + rz_core_theme_load(core, themeName.toUtf8().constData()); theme = Core()->cmdj("ecj").object().toVariantMap(); - rz_core_load_theme(core, curr.toUtf8().constData()); + rz_core_theme_load(core, curr.toUtf8().constData()); } else { theme = Core()->cmdj("ecj").object().toVariantMap(); } diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 3c309e83..5bb7a7ef 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -530,7 +530,7 @@ void Configuration::setColorTheme(const QString &theme) Core()->cmdRaw("ecd"); s.setValue("theme", "default"); } else { - rz_core_load_theme(Core()->core(), theme.toUtf8().constData()); + rz_core_theme_load(Core()->core(), theme.toUtf8().constData()); s.setValue("theme", theme); } diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 92cf4acb..fbcff262 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -187,7 +187,7 @@ void CutterCore::initialize(bool loadPlugins) #if defined(CUTTER_ENABLE_PACKAGING) && defined(Q_OS_WIN) auto prefixBytes = prefix.absolutePath().toUtf8(); - rz_sys_prefix(prefixBytes.constData()); + rz_path_prefix(prefixBytes.constData()); #endif rz_cons_new(); // initialize console @@ -225,7 +225,7 @@ void CutterCore::initialize(bool loadPlugins) setConfig("cfg.plugins", 0); } if (getConfigi("cfg.plugins")) { - rz_core_loadlibs(this->core_, RZ_CORE_LOADLIBS_ALL, nullptr); + rz_core_loadlibs(this->core_, RZ_CORE_LOADLIBS_ALL); } // IMPLICIT rz_bin_iobind (core_->bin, core_->io); @@ -2416,7 +2416,7 @@ void CutterCore::addBreakpoint(const BreakpointDescription &config) RzBreakpointItem *breakpoint = nullptr; int watchpoint_prot = 0; if (config.hw) { - watchpoint_prot = config.permission & ~(RZ_BP_PROT_EXEC); + watchpoint_prot = config.permission & ~(RZ_PERM_X); } auto address = config.addr; @@ -3003,7 +3003,7 @@ QList CutterCore::getAllComments(const QString &filterType) CORE_LOCK(); QList ret; - QJsonArray commentsArray = cmdj("CCj").array(); + QJsonArray commentsArray = cmdj("CClj").array(); for (const QJsonValue &value : commentsArray) { QJsonObject commentObject = value.toObject(); @@ -3153,13 +3153,16 @@ QList CutterCore::getAllSections() section.paddr = sect->paddr; section.size = sect->size; section.perm = rz_str_rwx_i(sect->perm); - HtPP *digests = rz_core_bin_section_digests(core, sect, hashnames); - if (!digests) { - continue; + if (sect->size > 0) { + HtPP *digests = rz_core_bin_create_digests(core, sect->paddr, sect->size, hashnames); + if (!digests) { + continue; + } + const char *entropy = (const char *)ht_pp_find(digests, "entropy", NULL); + section.entropy = rz_str_get(entropy); + ht_pp_free(digests); } - const char *entropy = (const char *)ht_pp_find(digests, "entropy", NULL); - section.entropy = rz_str_get(entropy); - ht_pp_free(digests); + section.entropy = ""; sections << section; } @@ -3834,7 +3837,7 @@ QString CutterCore::listFlagsAsStringAt(RVA addr) QString CutterCore::nearestFlag(RVA offset, RVA *flagOffsetOut) { - auto r = cmdj(QString("fdj @") + QString::number(offset)).object(); + auto r = cmdj(QString("fdj @ ") + QString::number(offset)).object(); QString name = r.value("name").toString(); if (flagOffsetOut) { auto offsetValue = r.value("offset"); diff --git a/src/dialogs/BreakpointsDialog.cpp b/src/dialogs/BreakpointsDialog.cpp index 75c5f8b4..c4c3108a 100644 --- a/src/dialogs/BreakpointsDialog.cpp +++ b/src/dialogs/BreakpointsDialog.cpp @@ -86,9 +86,9 @@ BreakpointsDialog::BreakpointsDialog(const BreakpointDescription &breakpoint, QW ui->breakpointCondition->setEditText(breakpoint.condition); if (breakpoint.hw) { ui->radioHardware->setChecked(true); - ui->hwRead->setChecked(breakpoint.permission & RZ_BP_PROT_READ); - ui->hwWrite->setChecked(breakpoint.permission & RZ_BP_PROT_WRITE); - ui->hwExecute->setChecked(breakpoint.permission & RZ_BP_PROT_EXEC); + ui->hwRead->setChecked(breakpoint.permission & RZ_PERM_R); + ui->hwWrite->setChecked(breakpoint.permission & RZ_PERM_W); + ui->hwExecute->setChecked(breakpoint.permission & RZ_PERM_X); ui->breakpointSize->setCurrentText(QString::number(breakpoint.size)); } else { ui->radioSoftware->setChecked(true); @@ -204,13 +204,13 @@ int BreakpointsDialog::getHwPermissions() { int result = 0; if (ui->hwRead->isChecked()) { - result |= RZ_BP_PROT_READ; + result |= RZ_PERM_R; } if (ui->hwWrite->isChecked()) { - result |= RZ_BP_PROT_WRITE; + result |= RZ_PERM_W; } if (ui->hwExecute->isChecked()) { - result |= RZ_BP_PROT_EXEC; + result |= RZ_PERM_X; } return result; } diff --git a/src/widgets/BreakpointWidget.cpp b/src/widgets/BreakpointWidget.cpp index ceb5636d..967e13a8 100644 --- a/src/widgets/BreakpointWidget.cpp +++ b/src/widgets/BreakpointWidget.cpp @@ -32,13 +32,13 @@ int BreakpointModel::columnCount(const QModelIndex &) const static QString formatHwBreakpoint(int permission) { char data[] = "rwx"; - if ((permission & (RZ_BP_PROT_READ | RZ_BP_PROT_ACCESS)) == 0) { + if ((permission & (RZ_PERM_R | RZ_PERM_RW)) == 0) { data[0] = '-'; } - if ((permission & (RZ_BP_PROT_WRITE | RZ_BP_PROT_ACCESS)) == 0) { + if ((permission & (RZ_PERM_W | RZ_PERM_RW)) == 0) { data[1] = '-'; } - if ((permission & RZ_BP_PROT_EXEC) == 0) { + if ((permission & RZ_PERM_X) == 0) { data[2] = '-'; } return data; From 9e77cf1362d187699b7266b3770be8b1f6cf1100 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sun, 26 Dec 2021 10:07:59 +0100 Subject: [PATCH 065/240] Bump version to 2.0.5 from stable (#2865) --- .appveyor.yml | 2 +- CMakeLists.txt | 2 +- docs/source/conf.py | 2 +- src/re.rizin.cutter.appdata.xml | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 9d0bf2f5..4f0866ae 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -version: '2.0.4-git-{build}' +version: '2.0.5-git-{build}' image: 'Visual Studio 2017' clone_depth: 1 diff --git a/CMakeLists.txt b/CMakeLists.txt index bfdc7e6c..92b49af4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,7 +34,7 @@ endif() set(CUTTER_VERSION_MAJOR 2) set(CUTTER_VERSION_MINOR 0) -set(CUTTER_VERSION_PATCH 4) +set(CUTTER_VERSION_PATCH 5) set(CUTTER_VERSION_FULL "${CUTTER_VERSION_MAJOR}.${CUTTER_VERSION_MINOR}.${CUTTER_VERSION_PATCH}") diff --git a/docs/source/conf.py b/docs/source/conf.py index f366fc03..ba34c0fb 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -26,7 +26,7 @@ author = 'The Cutter Developers' # The short X.Y version version = '2.0' # The full version, including a2lpha/beta/rc tags -release = '2.0.4' +release = '2.0.5' # -- General configuration --------------------------------------------------- diff --git a/src/re.rizin.cutter.appdata.xml b/src/re.rizin.cutter.appdata.xml index cfec367e..a622e5cd 100644 --- a/src/re.rizin.cutter.appdata.xml +++ b/src/re.rizin.cutter.appdata.xml @@ -25,6 +25,7 @@ xarkes + From 37064e8a21c89e691bf55a6e508f14d67df79a03 Mon Sep 17 00:00:00 2001 From: nirkog Date: Sat, 8 Jan 2022 13:07:20 +0200 Subject: [PATCH 066/240] Added support for ctrl+Enter submission in open shellcode tab (#2851) * Added support for ctrl+Enter submission in shellcode tab in the new file dialog --- src/dialogs/NewFileDialog.cpp | 32 ++++++++++++++++++++++++++++++++ src/dialogs/NewFileDialog.h | 2 ++ 2 files changed, 34 insertions(+) diff --git a/src/dialogs/NewFileDialog.cpp b/src/dialogs/NewFileDialog.cpp index a45aa75c..cde5fc85 100644 --- a/src/dialogs/NewFileDialog.cpp +++ b/src/dialogs/NewFileDialog.cpp @@ -75,6 +75,9 @@ NewFileDialog::NewFileDialog(MainWindow *main) /* Set focus on the TextInput */ ui->newFileEdit->setFocus(); + /* Install an event filter for shellcode text edit to enable ctrl+return event */ + ui->shellcodeText->installEventFilter(this); + updateLoadProjectButton(); } @@ -366,3 +369,32 @@ void NewFileDialog::on_tabWidget_currentChanged(int index) { Config()->setNewFileLastClicked(index); } + +bool NewFileDialog::eventFilter(QObject * /*obj*/, QEvent *event) +{ + QString shellcode = ui->shellcodeText->toPlainText(); + QString extractedCode = ""; + static const QRegularExpression rx("([0-9a-f]{2})", QRegularExpression::CaseInsensitiveOption); + QRegularExpressionMatchIterator i = rx.globalMatch(shellcode); + int size = 0; + + if (event->type() == QEvent::KeyPress) { + QKeyEvent *keyEvent = static_cast(event); + + // Confirm comment by pressing Ctrl/Cmd+Return + if ((keyEvent->modifiers() & Qt::ControlModifier) + && ((keyEvent->key() == Qt::Key_Enter) || (keyEvent->key() == Qt::Key_Return))) { + while (i.hasNext()) { + QRegularExpressionMatch match = i.next(); + extractedCode.append(match.captured(1)); + } + size = extractedCode.size() / 2; + if (size > 0) { + loadShellcode(extractedCode, size); + } + return true; + } + } + + return false; +} diff --git a/src/dialogs/NewFileDialog.h b/src/dialogs/NewFileDialog.h index 197f0508..eb5cb542 100644 --- a/src/dialogs/NewFileDialog.h +++ b/src/dialogs/NewFileDialog.h @@ -69,6 +69,8 @@ private: void loadProject(const QString &project); void loadShellcode(const QString &shellcode, const int size); + bool eventFilter(QObject *obj, QEvent *event); + static const int MaxRecentFiles = 5; }; From 71297ad118424434d7e5070e35ca4c81e3b7ffd2 Mon Sep 17 00:00:00 2001 From: nirkog Date: Sat, 8 Jan 2022 15:53:27 +0200 Subject: [PATCH 067/240] Add double click to seek to global var in decompiler (#2871) --- src/widgets/DecompilerWidget.cpp | 32 +++++++++++++++++++++++++++++--- src/widgets/DecompilerWidget.h | 12 ++++++++++++ 2 files changed, 41 insertions(+), 3 deletions(-) diff --git a/src/widgets/DecompilerWidget.cpp b/src/widgets/DecompilerWidget.cpp index e45c8c8a..a6dd58af 100644 --- a/src/widgets/DecompilerWidget.cpp +++ b/src/widgets/DecompilerWidget.cpp @@ -115,6 +115,28 @@ Decompiler *DecompilerWidget::getCurrentDecompiler() return Core()->getDecompilerById(ui->decompilerComboBox->currentData().toString()); } +ut64 DecompilerWidget::findReference(size_t pos) +{ + size_t closestPos = SIZE_MAX; + ut64 closestOffset = RVA_INVALID; + void *iter; + rz_vector_foreach(&code->annotations, iter) + { + RzCodeAnnotation *annotation = (RzCodeAnnotation *)iter; + + if (!(annotation->type == RZ_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE) + || annotation->start > pos || annotation->end <= pos) { + continue; + } + if (closestPos != SIZE_MAX && closestPos >= annotation->start) { + continue; + } + closestPos = annotation->start; + closestOffset = annotation->reference.offset; + } + return closestOffset; +} + ut64 DecompilerWidget::offsetForPosition(size_t pos) { size_t closestPos = SIZE_MAX; @@ -123,7 +145,8 @@ ut64 DecompilerWidget::offsetForPosition(size_t pos) rz_vector_foreach(&code->annotations, iter) { RzCodeAnnotation *annotation = (RzCodeAnnotation *)iter; - if (annotation->type != RZ_CODE_ANNOTATION_TYPE_OFFSET || annotation->start > pos + + if (!(annotation->type == RZ_CODE_ANNOTATION_TYPE_OFFSET) || annotation->start > pos || annotation->end <= pos) { continue; } @@ -479,8 +502,11 @@ void DecompilerWidget::showDecompilerContextMenu(const QPoint &pt) void DecompilerWidget::seekToReference() { size_t pos = ui->textEdit->textCursor().position(); - RVA offset = offsetForPosition(pos); - seekable->seekToReference(offset); + RVA offset = findReference(pos); + if (offset != RVA_INVALID) { + seekable->seek(offset); + } + seekable->seekToReference(offsetForPosition(pos)); } bool DecompilerWidget::eventFilter(QObject *obj, QEvent *event) diff --git a/src/widgets/DecompilerWidget.h b/src/widgets/DecompilerWidget.h index 22d0abf7..015525af 100644 --- a/src/widgets/DecompilerWidget.h +++ b/src/widgets/DecompilerWidget.h @@ -198,6 +198,18 @@ private: * @param endPos - Position of the end of the range(inclusive). */ void gatherBreakpointInfo(RzAnnotatedCode &codeDecompiled, size_t startPos, size_t endPos); + /** + * @brief Finds the global variable reference that's closes to the specified position in the + * decompiled code. Same as offsetForPosition but for global references only + * + * @note If no global reference annotations are found at the given position, an RVA_INVALID is + * returned + * + * @param pos - Position in the decompiled code + * @return Address of the referenced global for the specified position, or RVA_INVALID if none + * is found + */ + ut64 findReference(size_t pos); /** * @brief Finds the offset that's closest to the specified position in the decompiled code. * From 239343bb204847f49f8e5ad312e0752d1d680279 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 8 Jan 2022 17:16:41 +0100 Subject: [PATCH 068/240] Fix pdj call in nextOpAddr for disasm scrolling (#2874) --- src/core/Cutter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index fbcff262..87d52b15 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -991,7 +991,7 @@ RVA CutterCore::nextOpAddr(RVA startAddr, int count) CORE_LOCK(); QJsonArray array = - Core()->cmdj("pdj " + QString::number(count + 1) + "@" + QString::number(startAddr)) + Core()->cmdj("pdj " + QString::number(count + 1) + " @ " + QString::number(startAddr)) .array(); if (array.isEmpty()) { return startAddr + 1; From 75c334596ebbac9edac5a43f91a9577caa12d529 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Sat, 15 Jan 2022 21:02:01 +0100 Subject: [PATCH 069/240] Enable support for building rz-libswift on cutter (#2841) --- .github/workflows/ccpp.yml | 3 +++ CMakeLists.txt | 1 + dist/CMakeLists.txt | 23 +++++++++++++++++++++++ dist/bundle_rz_libswift.ps1 | 16 ++++++++++++++++ scripts/rz-libswift.sh | 19 +++++++++++++++++++ src/menus/DecompilerContextMenu.cpp | 2 +- 6 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 dist/bundle_rz_libswift.ps1 create mode 100755 scripts/rz-libswift.sh diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 789e1def..e567c6b9 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -121,6 +121,7 @@ jobs: -DCUTTER_ENABLE_PACKAGING=ON \ -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON \ -DCUTTER_PACKAGE_RZ_GHIDRA=ON \ + -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \ -DCMAKE_INSTALL_PREFIX=appdir/usr \ -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON \ .. @@ -187,6 +188,7 @@ jobs: -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON \ -DCUTTER_PACKAGE_RZ_GHIDRA=ON \ -DCUTTER_PACKAGE_JSDEC=ON \ + -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \ -DCPACK_PACKAGE_FILE_NAME="$PACKAGE_NAME" \ -DCMAKE_FRAMEWORK_PATH="$BREAKPAD_FRAMEWORK_DIR" \ -DCPACK_BUNDLE_APPLE_CERT_APP="-" \ @@ -224,6 +226,7 @@ jobs: -DCUTTER_ENABLE_PACKAGING=ON ^ -DCUTTER_PACKAGE_DEPENDENCIES=ON ^ -DCUTTER_PACKAGE_RZ_GHIDRA=ON ^ + -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON ^ -DCUTTER_PACKAGE_JSDEC=ON ^ -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON ^ -DCUTTER_ENABLE_CRASH_REPORTS=ON ^ diff --git a/CMakeLists.txt b/CMakeLists.txt index 92b49af4..9c0f30b5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ option(CUTTER_ENABLE_DEPENDENCY_DOWNLOADS "Enable downloading of dependencies. S option(CUTTER_ENABLE_PACKAGING "Enable building platform-specific packages for distributing" OFF) option(CUTTER_PACKAGE_DEPENDENCIES "During install step include the third party dependencies." OFF) option(CUTTER_PACKAGE_RZ_GHIDRA "Compile and install rz-ghidra during install step." OFF) +option(CUTTER_PACKAGE_RZ_LIBSWIFT, "Compile and install rz-libswift demangler during the install step." OFF) option(CUTTER_PACKAGE_JSDEC "Compile and install jsdec during install step." OFF) OPTION(CUTTER_QT6 "Use QT6" OFF) diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index cf57cc66..6ce64463 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -32,6 +32,18 @@ if(WIN32) endif() ") endif() + if (CUTTER_PACKAGE_RZ_LIBSWIFT AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) + install(CODE " + set(ENV{RZ_PREFIX} \"\${CMAKE_INSTALL_PREFIX}\") + set(ENV{PATH} \"\${CMAKE_INSTALL_PREFIX};\$ENV{PATH}\") + execute_process(COMMAND powershell \"${CMAKE_CURRENT_SOURCE_DIR}/bundle_rz_libswift.ps1\" \"\${CMAKE_INSTALL_PREFIX}\" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE SCRIPT_RESULT) + if (SCRIPT_RESULT) + message(FATAL_ERROR \"Failed to package rz-libswift\") + endif() + ") + endif() endif() ################################################ @@ -93,6 +105,17 @@ if(APPLE) ") endif() + if (CUTTER_PACKAGE_RZ_LIBSWIFT AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) + install(CODE " + execute_process(COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/rz-libswift.sh\" --pkg-config-path=\${CMAKE_INSTALL_PREFIX}/lib/pkgconfig --prefix=\${CMAKE_INSTALL_PREFIX} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE SCRIPT_RESULT) + if (SCRIPT_RESULT) + message(FATAL_ERROR \"Failed to package rz-libswift\") + endif() + ") + endif() + endif() ################################################ diff --git a/dist/bundle_rz_libswift.ps1 b/dist/bundle_rz_libswift.ps1 new file mode 100644 index 00000000..12928c93 --- /dev/null +++ b/dist/bundle_rz_libswift.ps1 @@ -0,0 +1,16 @@ +$dist = $args[0] +$python = Split-Path((Get-Command python.exe).Path) + +if (-not (Test-Path -Path 'libswift' -PathType Container)) { + git clone https://github.com/rizinorg/rz-libswift.git --depth 1 libswift +} +cd libswift +& meson.exe --buildtype=release --prefix=$dist build +ninja -C build install +$pathdll = "$dist/lib/plugins/swift.dll" +if(![System.IO.File]::Exists($pathdll)) { + type build/meson-logs/meson-log.txt + ls "$dist/lib/plugins/" + throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll)) +} +Remove-Item -Recurse -Force $dist/lib/plugins/libswift.lib diff --git a/scripts/rz-libswift.sh b/scripts/rz-libswift.sh new file mode 100755 index 00000000..0772cb4c --- /dev/null +++ b/scripts/rz-libswift.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +set -e + +SCRIPTPATH=$(realpath "$(dirname "${BASH_SOURCE[0]}")") + +cd "$SCRIPTPATH/.." + +if [[ ! -d libswift ]]; then + git clone https://github.com/rizinorg/rz-libswift.git --depth 1 libswift +fi + +cd libswift +rm -rf build || sleep 0 +mkdir build && cd build +meson --buildtype=release "$@" .. +ninja +ninja install + diff --git a/src/menus/DecompilerContextMenu.cpp b/src/menus/DecompilerContextMenu.cpp index e0e1baff..d36cf0b7 100644 --- a/src/menus/DecompilerContextMenu.cpp +++ b/src/menus/DecompilerContextMenu.cpp @@ -564,7 +564,7 @@ void DecompilerContextMenu::updateTargetMenuActions() RzCoreLocked core = Core()->core(); if (isReference()) { QString name; - QMenu *menu; + QMenu *menu = nullptr; if (annotationHere->type == RZ_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE || annotationHere->type == RZ_CODE_ANNOTATION_TYPE_CONSTANT_VARIABLE) { menu = mainWindow->createShowInMenu(this, annotationHere->reference.offset, From 46d29c1e85b207d43afcf5a68a8e25348a24e896 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Fri, 21 Jan 2022 09:39:56 +0100 Subject: [PATCH 070/240] Add signature widget for flirts (#2881) * Added flirt view and removed zignature one * Added menu for apply signature from file and create new sig/pat files * Updated rizin to dev branch --- .../menus/information-windows-menu.rst | 6 +- rizin | 2 +- src/CMakeLists.txt | 8 +- src/core/Cutter.cpp | 83 +++++--- src/core/Cutter.h | 6 +- src/core/CutterDescriptions.h | 20 +- src/core/MainWindow.cpp | 50 ++++- src/core/MainWindow.h | 8 +- src/core/MainWindow.ui | 13 ++ src/menus/FlirtContextMenu.cpp | 62 ++++++ src/menus/FlirtContextMenu.h | 40 ++++ src/widgets/FlirtWidget.cpp | 188 ++++++++++++++++++ src/widgets/FlirtWidget.h | 88 ++++++++ .../{ZignaturesWidget.ui => FlirtWidget.ui} | 8 +- src/widgets/ZignaturesWidget.cpp | 152 -------------- src/widgets/ZignaturesWidget.h | 78 -------- 16 files changed, 530 insertions(+), 282 deletions(-) create mode 100644 src/menus/FlirtContextMenu.cpp create mode 100644 src/menus/FlirtContextMenu.h create mode 100644 src/widgets/FlirtWidget.cpp create mode 100644 src/widgets/FlirtWidget.h rename src/widgets/{ZignaturesWidget.ui => FlirtWidget.ui} (90%) delete mode 100644 src/widgets/ZignaturesWidget.cpp delete mode 100644 src/widgets/ZignaturesWidget.h diff --git a/docs/source/user-docs/menus/information-windows-menu.rst b/docs/source/user-docs/menus/information-windows-menu.rst index 070fdfc6..ee35bbff 100644 --- a/docs/source/user-docs/menus/information-windows-menu.rst +++ b/docs/source/user-docs/menus/information-windows-menu.rst @@ -89,8 +89,8 @@ Show VTables **Steps:** Windows -> Info... -> VTables -Show Zignatures +Show Signatures ---------------------------------------- -**Description:** Cutter has its own format of signatures, called Zignatures. This widget lists all the loaded Zignatures. +**Description:** Cutter supports the creation and the utilization of signatures. This widget lists all the signatures available to cutter. -**Steps:** Windows -> Info... -> Zignatures \ No newline at end of file +**Steps:** Windows -> Info... -> Signatures \ No newline at end of file diff --git a/rizin b/rizin index 0e87fbd8..789a283d 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 0e87fbd8107dfe463924b498c84687cfc5fe2b7f +Subproject commit 789a283dd565dadebd17ab33cbfb5ec06d87323b diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8aae0d5d..eb556529 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -42,6 +42,7 @@ set(SOURCES widgets/SymbolsWidget.cpp menus/DisassemblyContextMenu.cpp menus/DecompilerContextMenu.cpp + menus/FlirtContextMenu.cpp widgets/DisassemblyWidget.cpp widgets/HexdumpWidget.cpp common/Configuration.cpp @@ -73,7 +74,7 @@ set(SOURCES common/JsonTreeItem.cpp common/JsonModel.cpp dialogs/VersionInfoDialog.cpp - widgets/ZignaturesWidget.cpp + widgets/FlirtWidget.cpp common/AsyncTask.cpp dialogs/AsyncTaskDialog.cpp widgets/StackWidget.cpp @@ -190,6 +191,7 @@ set(HEADER_FILES widgets/SymbolsWidget.h menus/DisassemblyContextMenu.h menus/DecompilerContextMenu.h + menus/FlirtContextMenu.h widgets/DisassemblyWidget.h widgets/HexdumpWidget.h common/Configuration.h @@ -221,7 +223,7 @@ set(HEADER_FILES common/JsonTreeItem.h common/JsonModel.h dialogs/VersionInfoDialog.h - widgets/ZignaturesWidget.h + widgets/FlirtWidget.h common/AsyncTask.h dialogs/AsyncTaskDialog.h widgets/StackWidget.h @@ -341,7 +343,7 @@ set(UI_FILES widgets/SearchWidget.ui dialogs/RizinPluginsDialog.ui dialogs/VersionInfoDialog.ui - widgets/ZignaturesWidget.ui + widgets/FlirtWidget.ui dialogs/AsyncTaskDialog.ui dialogs/RizinTaskDialog.ui widgets/StackWidget.ui diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 87d52b15..adf0d0e9 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1016,6 +1016,40 @@ RVA CutterCore::getOffset() return core_->offset; } +void CutterCore::applySignature(const QString &filepath) +{ + CORE_LOCK(); + int old_cnt, new_cnt; + const char *arch = rz_config_get(core->config, "asm.arch"); + ut8 expected_arch = rz_core_flirt_arch_from_name(arch); + if (expected_arch == RZ_FLIRT_SIG_ARCH_ANY && filepath.endsWith(".sig", Qt::CaseInsensitive)) { + QMessageBox::warning( + nullptr, tr("Signatures"), + tr("Cannot apply signature because the requested arch is not supported by .sig " + "files\n")); + return; + } + old_cnt = rz_flag_count(core->flags, "flirt"); + rz_sign_flirt_apply(core->analysis, filepath.toStdString().c_str(), expected_arch); + new_cnt = rz_flag_count(core->flags, "flirt"); + QMessageBox::information(nullptr, tr("Signatures"), + tr("Found %1 signatures!").arg(new_cnt - old_cnt)); +} + +void CutterCore::createSignature(const QString &filepath) +{ + CORE_LOCK(); + ut32 n_modules = 0; + if (!rz_core_flirt_create_file(core, filepath.toStdString().c_str(), &n_modules)) { + QMessageBox::warning( + nullptr, tr("Signatures"), + tr("Cannot create signature file (check the console for more details).\n")); + return; + } + QMessageBox::information(nullptr, tr("Signatures"), + tr("Written %1 signatures to %2").arg(n_modules).arg(filepath)); +} + ut64 CutterCore::math(const QString &expr) { CORE_LOCK(); @@ -2967,35 +3001,34 @@ QList CutterCore::getAllHeaders() return ret; } -QList CutterCore::getAllZignatures() +QList CutterCore::getSignaturesDB() { CORE_LOCK(); - QList zignatures; - - QJsonArray zignaturesArray = cmdj("zj").array(); - - for (const QJsonValue &value : zignaturesArray) { - QJsonObject zignatureObject = value.toObject(); - - ZignatureDescription zignature; - - zignature.name = zignatureObject[RJsonKey::name].toString(); - zignature.bytes = zignatureObject[RJsonKey::bytes].toString(); - zignature.offset = zignatureObject[RJsonKey::offset].toVariant().toULongLong(); - for (const QJsonValue &ref : zignatureObject[RJsonKey::refs].toArray()) { - zignature.refs << ref.toString(); - } - - QJsonObject graphObject = zignatureObject[RJsonKey::graph].toObject(); - zignature.cc = graphObject[RJsonKey::cc].toVariant().toULongLong(); - zignature.nbbs = graphObject[RJsonKey::nbbs].toVariant().toULongLong(); - zignature.edges = graphObject[RJsonKey::edges].toVariant().toULongLong(); - zignature.ebbs = graphObject[RJsonKey::ebbs].toVariant().toULongLong(); - - zignatures << zignature; + QList sigdb; + const char *sigdb_path = rz_config_get(core->config, "flirt.sigdb.path"); + if (RZ_STR_ISEMPTY(sigdb_path)) { + return sigdb; } - return zignatures; + RzList *list = rz_sign_sigdb_load_database(sigdb_path, true); + void *ptr = NULL; + RzListIter *iter = NULL; + + rz_list_foreach(list, iter, ptr) + { + RzSigDBEntry *sig = static_cast(ptr); + FlirtDescription flirt; + flirt.bin_name = sig->bin_name; + flirt.arch_name = sig->arch_name; + flirt.base_name = sig->base_name; + flirt.short_path = sig->short_path; + flirt.file_path = sig->file_path; + flirt.details = sig->details; + flirt.n_modules = QString::number(sig->n_modules); + flirt.arch_bits = QString::number(sig->arch_bits); + sigdb << flirt; + } + return sigdb; } QList CutterCore::getAllComments(const QString &filterType) diff --git a/src/core/Cutter.h b/src/core/Cutter.h index fbd73b6e..8671b73a 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -316,6 +316,10 @@ public: RVA prevOpAddr(RVA startAddr, int count); RVA nextOpAddr(RVA startAddr, int count); + /* SigDB / Flirt functions */ + void applySignature(const QString &filepath); + void createSignature(const QString &filepath); + /* Math functions */ ut64 math(const QString &expr); ut64 num(const QString &expr); @@ -553,7 +557,7 @@ public: QList getAllExports(); QList getAllSymbols(); QList getAllHeaders(); - QList getAllZignatures(); + QList getSignaturesDB(); QList getAllComments(const QString &filterType); QList getAllRelocs(); QList getAllStrings(); diff --git a/src/core/CutterDescriptions.h b/src/core/CutterDescriptions.h index 941be488..e28894ee 100644 --- a/src/core/CutterDescriptions.h +++ b/src/core/CutterDescriptions.h @@ -60,16 +60,16 @@ struct HeaderDescription QString name; }; -struct ZignatureDescription +struct FlirtDescription { - QString name; - QString bytes; - RVA cc; - RVA nbbs; - RVA edges; - RVA ebbs; - RVA offset; - QStringList refs; + QString bin_name; + QString arch_name; + QString arch_bits; + QString base_name; + QString short_path; + QString file_path; + QString details; + QString n_modules; }; struct TypeDescription @@ -413,7 +413,7 @@ Q_DECLARE_METATYPE(ResourcesDescription) Q_DECLARE_METATYPE(VTableDescription) Q_DECLARE_METATYPE(TypeDescription) Q_DECLARE_METATYPE(HeaderDescription) -Q_DECLARE_METATYPE(ZignatureDescription) +Q_DECLARE_METATYPE(FlirtDescription) Q_DECLARE_METATYPE(SearchDescription) Q_DECLARE_METATYPE(SectionDescription) Q_DECLARE_METATYPE(SegmentDescription) diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index 7d254031..6e796a8c 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -55,7 +55,7 @@ #include "widgets/ResourcesWidget.h" #include "widgets/VTablesWidget.h" #include "widgets/HeadersWidget.h" -#include "widgets/ZignaturesWidget.h" +#include "widgets/FlirtWidget.h" #include "widgets/DebugActions.h" #include "widgets/MemoryMapWidget.h" #include "widgets/BreakpointWidget.h" @@ -399,7 +399,7 @@ void MainWindow::initDocks() segmentsDock = new SegmentsWidget(this), symbolsDock = new SymbolsWidget(this), vTablesDock = new VTablesWidget(this), - zignaturesDock = new ZignaturesWidget(this), + flirtDock = new FlirtWidget(this), rzGraphDock = new RizinGraphWidget(this), callGraphDock = new CallGraphWidget(this, false), globalCallGraphDock = new CallGraphWidget(this, true), @@ -896,7 +896,7 @@ void MainWindow::restoreDocks() tabifyDockWidget(dashboardDock, typesDock); tabifyDockWidget(dashboardDock, searchDock); tabifyDockWidget(dashboardDock, headersDock); - tabifyDockWidget(dashboardDock, zignaturesDock); + tabifyDockWidget(dashboardDock, flirtDock); tabifyDockWidget(dashboardDock, symbolsDock); tabifyDockWidget(dashboardDock, classesDock); tabifyDockWidget(dashboardDock, resourcesDock); @@ -1741,6 +1741,50 @@ void MainWindow::on_actionExport_as_code_triggered() fileOut << Core()->cmd(cmd + " $s @ 0"); } +void MainWindow::on_actionApplySigFromFile_triggered() +{ + QStringList filters; + filters << tr("Signature File (*.sig)"); + filters << tr("Pattern File (*.pat)"); + + QFileDialog dialog(this); + dialog.setWindowTitle(tr("Apply Signature From File")); + dialog.setNameFilters(filters); + + if (!dialog.exec()) { + return; + } + + const QString &sigfile = QDir::toNativeSeparators(dialog.selectedFiles().first()); + + if (!sigfile.isEmpty()) { + core->applySignature(sigfile); + this->refreshAll(); + } +} + +void MainWindow::on_actionCreateNewSig_triggered() +{ + QStringList filters; + filters << tr("Signature File (*.sig)"); + filters << tr("Pattern File (*.pat)"); + + QFileDialog dialog(this, tr("Create New Signature File")); + dialog.setAcceptMode(QFileDialog::AcceptSave); + dialog.setFileMode(QFileDialog::AnyFile); + dialog.setNameFilters(filters); + dialog.selectFile(""); + dialog.setDefaultSuffix("sig"); + if (!dialog.exec()) + return; + + const QString &sigfile = QDir::toNativeSeparators(dialog.selectedFiles().first()); + + if (!sigfile.isEmpty()) { + core->createSignature(sigfile); + } +} + void MainWindow::on_actionGrouped_dock_dragging_triggered(bool checked) { #if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) diff --git a/src/core/MainWindow.h b/src/core/MainWindow.h index 312350cd..dd878062 100644 --- a/src/core/MainWindow.h +++ b/src/core/MainWindow.h @@ -44,7 +44,7 @@ class ResourcesWidget; class VTablesWidget; class TypesWidget; class HeadersWidget; -class ZignaturesWidget; +class FlirtWidget; class SearchWidget; class QDockWidget; class DisassemblyWidget; @@ -190,6 +190,10 @@ private slots: void on_actionExport_as_code_triggered(); + void on_actionApplySigFromFile_triggered(); + + void on_actionCreateNewSig_triggered(); + void on_actionGrouped_dock_dragging_triggered(bool checked); void updateTasksIndicator(); @@ -243,7 +247,7 @@ private: SdbWidget *sdbDock = nullptr; SectionsWidget *sectionsDock = nullptr; SegmentsWidget *segmentsDock = nullptr; - ZignaturesWidget *zignaturesDock = nullptr; + FlirtWidget *flirtDock = nullptr; ConsoleWidget *consoleDock = nullptr; ClassesWidget *classesDock = nullptr; ResourcesWidget *resourcesDock = nullptr; diff --git a/src/core/MainWindow.ui b/src/core/MainWindow.ui index dc9e4f1e..2af046cc 100644 --- a/src/core/MainWindow.ui +++ b/src/core/MainWindow.ui @@ -77,6 +77,9 @@ + + + @@ -740,6 +743,16 @@ Export as code + + + Apply Signature From File + + + + + Create New Signature File + + Add Hexdump diff --git a/src/menus/FlirtContextMenu.cpp b/src/menus/FlirtContextMenu.cpp new file mode 100644 index 00000000..cd573af0 --- /dev/null +++ b/src/menus/FlirtContextMenu.cpp @@ -0,0 +1,62 @@ +#include "FlirtContextMenu.h" +#include "MainWindow.h" + +#include +#include +#include +#include +#include +#include + +FlirtContextMenu::FlirtContextMenu(QWidget *parent, MainWindow *mainWindow) + : QMenu(parent), mainWindow(mainWindow) +{ + actionCopyLine = new QAction(tr("Copy Line"), this); + actionApplySignature = new QAction(tr("Apply Signature File"), this); + + connect(actionCopyLine, &QAction::triggered, this, &FlirtContextMenu::onActionCopyLine); + connect(actionApplySignature, &QAction::triggered, this, + &FlirtContextMenu::onActionApplySignature); + + addAction(actionCopyLine); + addSeparator(); + addAction(actionApplySignature); + + setHasTarget(false); +} + +FlirtContextMenu::~FlirtContextMenu() {} + +void FlirtContextMenu::setTarget(const FlirtDescription &flirt) +{ + this->entry = flirt; + setHasTarget(true); +} + +void FlirtContextMenu::clearTarget() +{ + setHasTarget(false); +} + +void FlirtContextMenu::onActionCopyLine() +{ + auto clipboard = QApplication::clipboard(); + QString text = entry.bin_name + "\t" + entry.arch_name + "\t" + entry.arch_bits + "\t" + + entry.n_modules + "\t" + entry.base_name + "\t" + entry.details; + clipboard->setText(text); +} + +void FlirtContextMenu::onActionApplySignature() +{ + if (this->hasTarget) { + Core()->applySignature(entry.file_path); + } +} + +void FlirtContextMenu::setHasTarget(bool hasTarget) +{ + this->hasTarget = hasTarget; + for (const auto &action : this->actions()) { + action->setEnabled(hasTarget); + } +} diff --git a/src/menus/FlirtContextMenu.h b/src/menus/FlirtContextMenu.h new file mode 100644 index 00000000..6cf12cae --- /dev/null +++ b/src/menus/FlirtContextMenu.h @@ -0,0 +1,40 @@ +#ifndef FLIRT_CONTEXTMENU_H +#define FLIRT_CONTEXTMENU_H + +#include "core/Cutter.h" +#include +#include + +class MainWindow; + +class CUTTER_EXPORT FlirtContextMenu : public QMenu +{ + Q_OBJECT + +public: + FlirtContextMenu(QWidget *parent, MainWindow *mainWindow); + ~FlirtContextMenu(); + +public slots: + void setTarget(const FlirtDescription &flirt); + void clearTarget(); + +private: + void onActionCopyLine(); + void onActionApplySignature(); + + QMenu *pluginMenu; + QAction *pluginMenuAction; + MainWindow *mainWindow; + + bool hasTarget = false; + +protected: + void setHasTarget(bool hasTarget); + QAction *actionApplySignature; + QAction *actionCopyLine; + QAction *actionShowContents; + + FlirtDescription entry; +}; +#endif // FlirtCONTEXTMENU_H diff --git a/src/widgets/FlirtWidget.cpp b/src/widgets/FlirtWidget.cpp new file mode 100644 index 00000000..61d43d87 --- /dev/null +++ b/src/widgets/FlirtWidget.cpp @@ -0,0 +1,188 @@ +#include "FlirtWidget.h" +#include "ui_FlirtWidget.h" +#include "core/MainWindow.h" +#include "common/Helpers.h" + +FlirtModel::FlirtModel(QList *sigdb, QObject *parent) + : QAbstractListModel(parent), sigdb(sigdb) +{ +} + +int FlirtModel::rowCount(const QModelIndex &) const +{ + return sigdb->count(); +} + +int FlirtModel::columnCount(const QModelIndex &) const +{ + return FlirtModel::ColumnCount; +} + +QVariant FlirtModel::data(const QModelIndex &index, int role) const +{ + if (index.row() >= sigdb->count()) + return QVariant(); + + const FlirtDescription &entry = sigdb->at(index.row()); + + switch (role) { + case Qt::DisplayRole: + switch (index.column()) { + case BinTypeColumn: + return entry.bin_name; + case ArchNameColumn: + return entry.arch_name; + case ArchBitsColumn: + return entry.arch_bits; + case NumModulesColumn: + return entry.n_modules; + case NameColumn: + return entry.base_name; + case DetailsColumn: + return entry.details; + default: + return QVariant(); + } + + case FlirtDescriptionRole: + return QVariant::fromValue(entry); + + case Qt::ToolTipRole: { + return entry.short_path; + } + + default: + return QVariant(); + } +} + +QVariant FlirtModel::headerData(int section, Qt::Orientation, int role) const +{ + switch (role) { + case Qt::DisplayRole: + switch (section) { + case BinTypeColumn: + return tr("Bin"); + case ArchNameColumn: + return tr("Arch"); + case ArchBitsColumn: + return tr("Bits"); + case NumModulesColumn: + return tr("# Funcs"); + case NameColumn: + return tr("Name"); + case DetailsColumn: + return tr("Details"); + default: + return QVariant(); + } + default: + return QVariant(); + } +} + +FlirtProxyModel::FlirtProxyModel(FlirtModel *sourceModel, QObject *parent) + : QSortFilterProxyModel(parent) +{ + setSourceModel(sourceModel); +} + +bool FlirtProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const +{ + QModelIndex index = sourceModel()->index(row, 0, parent); + FlirtDescription entry = index.data(FlirtModel::FlirtDescriptionRole).value(); + return qhelpers::filterStringContains(entry.base_name, this); +} + +bool FlirtProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const +{ + FlirtDescription leftEntry = + left.data(FlirtModel::FlirtDescriptionRole).value(); + FlirtDescription rightEntry = + right.data(FlirtModel::FlirtDescriptionRole).value(); + + switch (left.column()) { + case FlirtModel::BinTypeColumn: + return leftEntry.bin_name < rightEntry.bin_name; + case FlirtModel::ArchNameColumn: + return leftEntry.arch_name < rightEntry.arch_name; + case FlirtModel::ArchBitsColumn: + return leftEntry.arch_bits < rightEntry.arch_bits; + case FlirtModel::NumModulesColumn: + return leftEntry.n_modules < rightEntry.n_modules; + case FlirtModel::NameColumn: + return leftEntry.base_name < rightEntry.base_name; + case FlirtModel::DetailsColumn: + return leftEntry.details < rightEntry.details; + default: + break; + } + + return leftEntry.bin_name < rightEntry.bin_name; +} + +FlirtWidget::FlirtWidget(MainWindow *main) + : CutterDockWidget(main), + ui(new Ui::FlirtWidget), + blockMenu(new FlirtContextMenu(this, mainWindow)) +{ + ui->setupUi(this); + + model = new FlirtModel(&sigdb, this); + proxyModel = new FlirtProxyModel(model, this); + ui->flirtTreeView->setModel(proxyModel); + ui->flirtTreeView->sortByColumn(FlirtModel::BinTypeColumn, Qt::AscendingOrder); + + setScrollMode(); + + this->connect(this, &QWidget::customContextMenuRequested, this, + &FlirtWidget::showItemContextMenu); + this->setContextMenuPolicy(Qt::CustomContextMenu); + + this->connect(ui->flirtTreeView->selectionModel(), &QItemSelectionModel::currentChanged, this, + &FlirtWidget::onSelectedItemChanged); + connect(Core(), &CutterCore::refreshAll, this, &FlirtWidget::refreshFlirt); + + this->addActions(this->blockMenu->actions()); +} + +FlirtWidget::~FlirtWidget() {} + +void FlirtWidget::refreshFlirt() +{ + model->beginResetModel(); + sigdb = Core()->getSignaturesDB(); + model->endResetModel(); + + ui->flirtTreeView->resizeColumnToContents(0); + ui->flirtTreeView->resizeColumnToContents(1); + ui->flirtTreeView->resizeColumnToContents(2); + ui->flirtTreeView->resizeColumnToContents(3); + ui->flirtTreeView->resizeColumnToContents(4); + ui->flirtTreeView->resizeColumnToContents(5); +} + +void FlirtWidget::setScrollMode() +{ + qhelpers::setVerticalScrollMode(ui->flirtTreeView); +} + +void FlirtWidget::onSelectedItemChanged(const QModelIndex &index) +{ + if (index.isValid()) { + const FlirtDescription &entry = sigdb.at(index.row()); + blockMenu->setTarget(entry); + } else { + blockMenu->clearTarget(); + } +} + +void FlirtWidget::showItemContextMenu(const QPoint &pt) +{ + auto index = ui->flirtTreeView->currentIndex(); + if (index.isValid()) { + const FlirtDescription &entry = sigdb.at(index.row()); + blockMenu->setTarget(entry); + blockMenu->exec(this->mapToGlobal(pt)); + } +} \ No newline at end of file diff --git a/src/widgets/FlirtWidget.h b/src/widgets/FlirtWidget.h new file mode 100644 index 00000000..937e91f5 --- /dev/null +++ b/src/widgets/FlirtWidget.h @@ -0,0 +1,88 @@ +#ifndef FLIRT_WIDGET_H +#define FLIRT_WIDGET_H + +#include + +#include "core/Cutter.h" +#include "CutterDockWidget.h" +#include "menus/FlirtContextMenu.h" + +#include +#include + +class MainWindow; +class QTreeWidget; +class QTreeWidgetItem; +class FlirtWidget; + +namespace Ui { +class FlirtWidget; +} + +class FlirtModel : public QAbstractListModel +{ + Q_OBJECT + + friend FlirtWidget; + +public: + enum Column { + BinTypeColumn = 0, + ArchNameColumn, + ArchBitsColumn, + NumModulesColumn, + NameColumn, + DetailsColumn, + ColumnCount + }; + enum Role { FlirtDescriptionRole = Qt::UserRole }; + + FlirtModel(QList *sigdb, QObject *parent = 0); + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + +private: + QList *sigdb; +}; + +class FlirtProxyModel : public QSortFilterProxyModel +{ + Q_OBJECT + +public: + FlirtProxyModel(FlirtModel *sourceModel, QObject *parent = nullptr); + +protected: + bool filterAcceptsRow(int row, const QModelIndex &parent) const override; + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; +}; + +class FlirtWidget : public CutterDockWidget +{ + Q_OBJECT + +public: + explicit FlirtWidget(MainWindow *main); + ~FlirtWidget(); + +private slots: + void refreshFlirt(); + void onSelectedItemChanged(const QModelIndex &index); + void showItemContextMenu(const QPoint &pt); + +private: + std::unique_ptr ui; + + FlirtModel *model; + FlirtProxyModel *proxyModel; + QList sigdb; + FlirtContextMenu *blockMenu; + + void setScrollMode(); +}; + +#endif // FLIRT_WIDGET_H diff --git a/src/widgets/ZignaturesWidget.ui b/src/widgets/FlirtWidget.ui similarity index 90% rename from src/widgets/ZignaturesWidget.ui rename to src/widgets/FlirtWidget.ui index 4db82885..19b922e1 100644 --- a/src/widgets/ZignaturesWidget.ui +++ b/src/widgets/FlirtWidget.ui @@ -1,7 +1,7 @@ - ZignaturesWidget - + FlirtWidget + 0 @@ -11,7 +11,7 @@ - Zignatures + Signatures @@ -28,7 +28,7 @@ 0 - + CutterTreeView::item { diff --git a/src/widgets/ZignaturesWidget.cpp b/src/widgets/ZignaturesWidget.cpp deleted file mode 100644 index 222a4d09..00000000 --- a/src/widgets/ZignaturesWidget.cpp +++ /dev/null @@ -1,152 +0,0 @@ -#include "ZignaturesWidget.h" -#include "ui_ZignaturesWidget.h" -#include "core/MainWindow.h" -#include "common/Helpers.h" - -ZignaturesModel::ZignaturesModel(QList *zignatures, QObject *parent) - : QAbstractListModel(parent), zignatures(zignatures) -{ -} - -int ZignaturesModel::rowCount(const QModelIndex &) const -{ - return zignatures->count(); -} - -int ZignaturesModel::columnCount(const QModelIndex &) const -{ - return ZignaturesModel::ColumnCount; -} - -QVariant ZignaturesModel::data(const QModelIndex &index, int role) const -{ - if (index.row() >= zignatures->count()) - return QVariant(); - - const ZignatureDescription &zignature = zignatures->at(index.row()); - - switch (role) { - case Qt::DisplayRole: - switch (index.column()) { - case OffsetColumn: - return RzAddressString(zignature.offset); - case NameColumn: - return zignature.name; - case ValueColumn: - return zignature.bytes; - default: - return QVariant(); - } - - case ZignatureDescriptionRole: - return QVariant::fromValue(zignature); - - case Qt::ToolTipRole: { - QString tmp = QString("Graph:\n\n Cyclomatic complexity: " + RzSizeString(zignature.cc) - + "\n Nodes / basicblocks: " + RzSizeString(zignature.nbbs) - + "\n Edges: " + RzSizeString(zignature.edges) - + "\n Ebbs: " + RzSizeString(zignature.ebbs) + "\n\nRefs:\n"); - for (const QString &ref : zignature.refs) { - tmp.append("\n " + ref); - } - return tmp; - } - - default: - return QVariant(); - } -} - -QVariant ZignaturesModel::headerData(int section, Qt::Orientation, int role) const -{ - switch (role) { - case Qt::DisplayRole: - switch (section) { - case OffsetColumn: - return tr("Offset"); - case NameColumn: - return tr("Name"); - case ValueColumn: - return tr("Bytes"); - default: - return QVariant(); - } - default: - return QVariant(); - } -} - -ZignaturesProxyModel::ZignaturesProxyModel(ZignaturesModel *sourceModel, QObject *parent) - : QSortFilterProxyModel(parent) -{ - setSourceModel(sourceModel); -} - -bool ZignaturesProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const -{ - QModelIndex index = sourceModel()->index(row, 0, parent); - ZignatureDescription item = - index.data(ZignaturesModel::ZignatureDescriptionRole).value(); - return qhelpers::filterStringContains(item.name, this); -} - -bool ZignaturesProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const -{ - ZignatureDescription leftZignature = - left.data(ZignaturesModel::ZignatureDescriptionRole).value(); - ZignatureDescription rightZignature = - right.data(ZignaturesModel::ZignatureDescriptionRole).value(); - - switch (left.column()) { - case ZignaturesModel::OffsetColumn: - return leftZignature.offset < rightZignature.offset; - case ZignaturesModel::NameColumn: - return leftZignature.name < rightZignature.name; - case ZignaturesModel::ValueColumn: - return leftZignature.bytes < rightZignature.bytes; - default: - break; - } - - return leftZignature.offset < rightZignature.offset; -} - -ZignaturesWidget::ZignaturesWidget(MainWindow *main) - : CutterDockWidget(main), ui(new Ui::ZignaturesWidget) -{ - ui->setupUi(this); - - zignaturesModel = new ZignaturesModel(&zignatures, this); - zignaturesProxyModel = new ZignaturesProxyModel(zignaturesModel, this); - ui->zignaturesTreeView->setModel(zignaturesProxyModel); - ui->zignaturesTreeView->sortByColumn(ZignaturesModel::OffsetColumn, Qt::AscendingOrder); - - setScrollMode(); - - connect(Core(), &CutterCore::refreshAll, this, &ZignaturesWidget::refreshZignatures); -} - -ZignaturesWidget::~ZignaturesWidget() {} - -void ZignaturesWidget::refreshZignatures() -{ - zignaturesModel->beginResetModel(); - zignatures = Core()->getAllZignatures(); - zignaturesModel->endResetModel(); - - ui->zignaturesTreeView->resizeColumnToContents(0); - ui->zignaturesTreeView->resizeColumnToContents(1); - ui->zignaturesTreeView->resizeColumnToContents(2); -} - -void ZignaturesWidget::setScrollMode() -{ - qhelpers::setVerticalScrollMode(ui->zignaturesTreeView); -} - -void ZignaturesWidget::on_zignaturesTreeView_doubleClicked(const QModelIndex &index) -{ - ZignatureDescription item = - index.data(ZignaturesModel::ZignatureDescriptionRole).value(); - Core()->seekAndShow(item.offset); -} diff --git a/src/widgets/ZignaturesWidget.h b/src/widgets/ZignaturesWidget.h deleted file mode 100644 index 88a6d945..00000000 --- a/src/widgets/ZignaturesWidget.h +++ /dev/null @@ -1,78 +0,0 @@ -#ifndef ZIGNATURESWIDGET_H -#define ZIGNATURESWIDGET_H - -#include - -#include "core/Cutter.h" -#include "CutterDockWidget.h" - -#include -#include - -class MainWindow; -class QTreeWidget; -class QTreeWidgetItem; -class ZignaturesWidget; - -namespace Ui { -class ZignaturesWidget; -} - -class ZignaturesModel : public QAbstractListModel -{ - Q_OBJECT - - friend ZignaturesWidget; - -public: - enum Column { OffsetColumn = 0, NameColumn, ValueColumn, ColumnCount }; - enum Role { ZignatureDescriptionRole = Qt::UserRole }; - - ZignaturesModel(QList *zignatures, QObject *parent = 0); - - QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; - - int rowCount(const QModelIndex &parent = QModelIndex()) const; - int columnCount(const QModelIndex &parent = QModelIndex()) const; - -private: - QList *zignatures; -}; - -class ZignaturesProxyModel : public QSortFilterProxyModel -{ - Q_OBJECT - -public: - ZignaturesProxyModel(ZignaturesModel *sourceModel, QObject *parent = nullptr); - -protected: - bool filterAcceptsRow(int row, const QModelIndex &parent) const override; - bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; -}; - -class ZignaturesWidget : public CutterDockWidget -{ - Q_OBJECT - -public: - explicit ZignaturesWidget(MainWindow *main); - ~ZignaturesWidget(); - -private slots: - void on_zignaturesTreeView_doubleClicked(const QModelIndex &index); - - void refreshZignatures(); - -private: - std::unique_ptr ui; - - ZignaturesModel *zignaturesModel; - ZignaturesProxyModel *zignaturesProxyModel; - QList zignatures; - - void setScrollMode(); -}; - -#endif // ZIGNATURESWIDGET_H From 91d99ba2190f4796da268be376d9f06e3c7f31bc Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Fri, 21 Jan 2022 18:48:10 +0100 Subject: [PATCH 071/240] Return error when applying a signature fails. (#2882) * Updated rizin commit to 8282cee287abdbf8664a0b2540bad2b5ea5b819d * Fix messages based on fail/success result while applying a sig/pat file --- rizin | 2 +- src/core/Cutter.cpp | 25 +++++++++++++++---------- 2 files changed, 16 insertions(+), 11 deletions(-) diff --git a/rizin b/rizin index 789a283d..8282cee2 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 789a283dd565dadebd17ab33cbfb5ec06d87323b +Subproject commit 8282cee287abdbf8664a0b2540bad2b5ea5b819d diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index adf0d0e9..261ca99a 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1023,17 +1023,22 @@ void CutterCore::applySignature(const QString &filepath) const char *arch = rz_config_get(core->config, "asm.arch"); ut8 expected_arch = rz_core_flirt_arch_from_name(arch); if (expected_arch == RZ_FLIRT_SIG_ARCH_ANY && filepath.endsWith(".sig", Qt::CaseInsensitive)) { - QMessageBox::warning( - nullptr, tr("Signatures"), - tr("Cannot apply signature because the requested arch is not supported by .sig " - "files\n")); + QMessageBox::warning(nullptr, tr("Signatures"), + tr("Cannot apply signature file because the requested arch is not " + "supported by .sig " + "files")); return; } old_cnt = rz_flag_count(core->flags, "flirt"); - rz_sign_flirt_apply(core->analysis, filepath.toStdString().c_str(), expected_arch); - new_cnt = rz_flag_count(core->flags, "flirt"); - QMessageBox::information(nullptr, tr("Signatures"), - tr("Found %1 signatures!").arg(new_cnt - old_cnt)); + if (rz_sign_flirt_apply(core->analysis, filepath.toStdString().c_str(), expected_arch)) { + new_cnt = rz_flag_count(core->flags, "flirt"); + QMessageBox::information(nullptr, tr("Signatures"), + tr("Found %1 matching signatures!").arg(new_cnt - old_cnt)); + return; + } + QMessageBox::warning( + nullptr, tr("Signatures"), + tr("Failed to apply signature file!\nPlease check the console for more details.")); } void CutterCore::createSignature(const QString &filepath) @@ -1043,11 +1048,11 @@ void CutterCore::createSignature(const QString &filepath) if (!rz_core_flirt_create_file(core, filepath.toStdString().c_str(), &n_modules)) { QMessageBox::warning( nullptr, tr("Signatures"), - tr("Cannot create signature file (check the console for more details).\n")); + tr("Cannot create signature file (check the console for more details).")); return; } QMessageBox::information(nullptr, tr("Signatures"), - tr("Written %1 signatures to %2").arg(n_modules).arg(filepath)); + tr("Written %1 signatures to %2.").arg(n_modules).arg(filepath)); } ut64 CutterCore::math(const QString &expr) From 734abd5609f42e927c24024ea17a84bc1932dd1d Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Wed, 26 Jan 2022 15:53:05 +0200 Subject: [PATCH 072/240] Fix crash on Windows when starting from a console (#2885) Fixes #2877 --- src/Main.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Main.cpp b/src/Main.cpp index 0e665061..89101b11 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -22,14 +22,19 @@ static void connectToConsole() return; } - // Avoid reconfiguring stderr/stdout if one of them is already connected to a stream. + // Avoid reconfiguring stdin/stderr/stdout if one of them is already connected to a stream. // This can happen when running with stdout/stderr redirected to a file. - if (0 > fileno(stdout)) { - // Overwrite FD 1 and 2 for the benefit of any code that uses the FDs + if (0 > fileno(stdin)) { + // Overwrite FD 0, FD 1 and 2 for the benefit of any code that uses the FDs // directly. This is safe because the CRT allocates FDs 0, 1 and // 2 at startup even if they don't have valid underlying Windows // handles. This means we won't be overwriting an FD created by // _open() after startup. + _close(0); + + freopen("CONIN$", "r+", stdin); + } + if (0 > fileno(stdout)) { _close(1); if (freopen("CONOUT$", "a+", stdout)) { From 97b3aaaa3f649c9dead48b89d0811cd0716f71c7 Mon Sep 17 00:00:00 2001 From: billow Date: Thu, 27 Jan 2022 17:06:20 +0800 Subject: [PATCH 073/240] Convert rizin commands to C apis (#2861) * "fr" renameFlag * "f-" delFlag * "f" addFlag * "fsj" getAllFlagspaces * "fj" getAllFlags * "afn" renameFunction * "af-" delFunction * "af" createFunctionAt * "eco" * "ecd" --- rizin | 2 +- src/common/Configuration.cpp | 2 +- src/common/SettingsUpgrade.cpp | 8 +- src/core/Cutter.cpp | 135 +++++++++++++++------------ src/core/Cutter.h | 11 ++- src/dialogs/EditVariablesDialog.cpp | 2 +- src/menus/DisassemblyContextMenu.cpp | 2 +- src/widgets/FunctionsWidget.cpp | 5 +- 8 files changed, 96 insertions(+), 71 deletions(-) diff --git a/rizin b/rizin index 8282cee2..d43cbf5c 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 8282cee287abdbf8664a0b2540bad2b5ea5b819d +Subproject commit d43cbf5ce74fd7333032144a8e0fc2f74ce9803a diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 5bb7a7ef..87a97b92 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -527,7 +527,7 @@ const QColor Configuration::getColor(const QString &name) const void Configuration::setColorTheme(const QString &theme) { if (theme == "default") { - Core()->cmdRaw("ecd"); + rz_cons_pal_init(Core()->core()->cons->context); s.setValue("theme", "default"); } else { rz_core_theme_load(Core()->core(), theme.toUtf8().constData()); diff --git a/src/common/SettingsUpgrade.cpp b/src/common/SettingsUpgrade.cpp index 33b5bff9..9ff48999 100644 --- a/src/common/SettingsUpgrade.cpp +++ b/src/common/SettingsUpgrade.cpp @@ -183,8 +183,11 @@ static void removeObsoleteOptionsFromCustomThemes() { const QStringList options = Core()->cmdj("ecj").object().keys() << ColorThemeWorker::cutterSpecificOptions; - for (auto theme : Core()->cmdList("eco*")) { - theme = theme.trimmed(); + RzList *themes_list = rz_core_theme_list(Core()->core()); + RzListIter *th_iter; + const char *th; + CutterRzListForeach (themes_list, th_iter, const char, th) { + auto theme = QString(th).trimmed(); if (!ThemeWorker().isCustomTheme(theme)) { continue; } @@ -197,6 +200,7 @@ static void removeObsoleteOptionsFromCustomThemes() } ThemeWorker().save(QJsonDocument(updatedTheme), theme); } + rz_list_free(themes_list); } void Cutter::migrateThemes() diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 261ca99a..21a07c57 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -687,19 +687,25 @@ bool CutterCore::mapFile(QString path, RVA mapaddr) void CutterCore::renameFunction(const RVA offset, const QString &newName) { - cmdRaw("afn " + newName + " " + RzAddressString(offset)); + CORE_LOCK(); + rz_core_analysis_function_rename(core, offset, newName.toStdString().c_str()); emit functionRenamed(offset, newName); } void CutterCore::delFunction(RVA addr) { - cmdRaw("af- " + RzAddressString(addr)); + CORE_LOCK(); + rz_core_analysis_undefine(core, addr); emit functionsChanged(); } void CutterCore::renameFlag(QString old_name, QString new_name) { - cmdRaw("fr " + old_name + " " + new_name); + CORE_LOCK(); + RzFlagItem *flag = rz_flag_get(core->flags, old_name.toStdString().c_str()); + if (!flag) + return; + rz_flag_rename(core->flags, flag, new_name.toStdString().c_str()); emit flagsChanged(); } @@ -717,13 +723,15 @@ void CutterCore::renameFunctionVariable(QString newName, QString oldName, RVA fu void CutterCore::delFlag(RVA addr) { - cmdRawAt("f-", addr); + CORE_LOCK(); + rz_flag_unset_off(core->flags, addr); emit flagsChanged(); } void CutterCore::delFlag(const QString &name) { - cmdRaw("f-" + name); + CORE_LOCK(); + rz_flag_unset_name(core->flags, name.toStdString().c_str()); emit flagsChanged(); } @@ -797,34 +805,34 @@ void CutterCore::setAsString(RVA addr, int size, StringTypeFormats type) return; } - QString command; - + RzStrEnc encoding; switch (type) { case StringTypeFormats::None: { - command = "Cs"; + encoding = RZ_STRING_ENC_GUESS; break; } case StringTypeFormats::ASCII_LATIN1: { - command = "Csa"; + encoding = RZ_STRING_ENC_8BIT; break; } case StringTypeFormats::UTF8: { - command = "Cs8"; + encoding = RZ_STRING_ENC_UTF8; break; } default: return; } + CORE_LOCK(); seekAndShow(addr); - - cmdRawAt(QString("%1 %2").arg(command).arg(size), addr); + rz_core_meta_string_add(core, addr, size, encoding, nullptr); emit instructionChanged(addr); } void CutterCore::removeString(RVA addr) { - cmdRawAt("Cs-", addr); + CORE_LOCK(); + rz_meta_del(core->analysis, RZ_META_TYPE_STRING, addr, 1); emit instructionChanged(addr); } @@ -833,21 +841,33 @@ QString CutterCore::getString(RVA addr) return cmdRawAt("ps", addr); } +QString CutterCore::getMetaString(RVA addr) +{ + return cmdRawAt("Cs.", addr); +} + void CutterCore::setToData(RVA addr, int size, int repeat) { if (size <= 0 || repeat <= 0) { return; } - cmdRawAt("Cd-", addr); - cmdRawAt(QString("Cd %1 %2").arg(size).arg(repeat), addr); + + CORE_LOCK(); + rz_meta_del(core->analysis, RZ_META_TYPE_DATA, addr, 1); + RVA address = addr; + auto name = QString(size).toStdString(); + for (int i = 0; i < repeat; ++i, address += size) { + rz_meta_set(core->analysis, RZ_META_TYPE_DATA, address, size, name.c_str()); + } emit instructionChanged(addr); } int CutterCore::sizeofDataMeta(RVA addr) { - bool ok; - int size = cmdRawAt("Cd.", addr).toInt(&ok); - return (ok ? size : 0); + ut64 size; + CORE_LOCK(); + rz_meta_get_at(core->analysis, addr, RZ_META_TYPE_DATA, &size); + return (int)size; } void CutterCore::setComment(RVA addr, const QString &cmt) @@ -1302,20 +1322,22 @@ void CutterCore::cmdEsil(const char *command) } } -QString CutterCore::createFunctionAt(RVA addr) +void CutterCore::createFunctionAt(RVA addr) { - QString ret = cmdRaw(QString("af %1").arg(addr)); - emit functionsChanged(); - return ret; + createFunctionAt(addr, ""); } -QString CutterCore::createFunctionAt(RVA addr, QString name) +void CutterCore::createFunctionAt(RVA addr, QString name) { - static const QRegularExpression regExp("[^a-zA-Z0-9_.]"); - name.remove(regExp); - QString ret = cmdRawAt(QString("af %1").arg(name), addr); + if (!name.isEmpty() && !name.isNull()) { + static const QRegularExpression regExp("[^a-zA-Z0-9_.]"); + name.remove(regExp); + } + + CORE_LOCK(); + bool analyze_recursively = rz_config_get_i(core->config, "analysis.calls"); + rz_core_analysis_function_add(core, name.toStdString().c_str(), addr, analyze_recursively); emit functionsChanged(); - return ret; } QJsonDocument CutterCore::getRegistersInfo() @@ -3118,45 +3140,37 @@ QList CutterCore::parseStringsJson(const QJsonDocument &doc) QList CutterCore::getAllFlagspaces() { CORE_LOCK(); - QList ret; - - QJsonArray flagspacesArray = cmdj("fsj").array(); - for (const QJsonValue &value : flagspacesArray) { - QJsonObject flagspaceObject = value.toObject(); - + QList flagspaces; + RzSpaceIter it; + RzSpace *space; + rz_flag_space_foreach(core->flags, it, space) + { FlagspaceDescription flagspace; - - flagspace.name = flagspaceObject[RJsonKey::name].toString(); - - ret << flagspace; + flagspace.name = space->name; + flagspaces << flagspace; } - return ret; + return flagspaces; } QList CutterCore::getAllFlags(QString flagspace) { CORE_LOCK(); - QList ret; - - if (!flagspace.isEmpty()) - cmdRaw("fs " + flagspace); - else - cmdRaw("fs *"); - - QJsonArray flagsArray = cmdj("fj").array(); - for (const QJsonValue &value : flagsArray) { - QJsonObject flagObject = value.toObject(); - - FlagDescription flag; - - flag.offset = flagObject[RJsonKey::offset].toVariant().toULongLong(); - flag.size = flagObject[RJsonKey::size].toVariant().toULongLong(); - flag.name = flagObject[RJsonKey::name].toString(); - flag.realname = flagObject[RJsonKey::realname].toString(); - - ret << flag; - } - return ret; + QList flags; + std::string name = flagspace.isEmpty() || flagspace.isNull() ? "*" : flagspace.toStdString(); + RzSpace *space = rz_flag_space_get(core->flags, name.c_str()); + rz_flag_foreach_space( + core->flags, space, + [](RzFlagItem *item, void *user) { + FlagDescription flag; + flag.offset = item->offset; + flag.size = item->size; + flag.name = item->name; + flag.realname = item->name; + reinterpret_cast *>(user)->append(flag); + return true; + }, + &flags); + return flags; } QList CutterCore::getAllSections() @@ -3856,7 +3870,8 @@ QList CutterCore::getXRefs(RVA addr, bool to, bool whole_functi void CutterCore::addFlag(RVA offset, QString name, RVA size) { name = sanitizeStringForCommand(name); - cmdRawAt(QString("f %1 %2").arg(name).arg(size), offset); + CORE_LOCK(); + rz_flag_set(core->flags, name.toStdString().c_str(), offset, size); emit flagsChanged(); } diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 8671b73a..d8b7a0a1 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -198,8 +198,8 @@ public: RVA getLastFunctionInstruction(RVA addr); QString cmdFunctionAt(QString addr); QString cmdFunctionAt(RVA addr); - QString createFunctionAt(RVA addr); - QString createFunctionAt(RVA addr, QString name); + void createFunctionAt(RVA addr); + void createFunctionAt(RVA addr, QString name); QStringList getDisassemblyPreview(RVA address, int num_of_lines); /* Flags */ @@ -242,6 +242,13 @@ public: * \param addr The address of the array where the string will be applied */ void removeString(RVA addr); + /** + * @brief Gets string at address + * That function correspond the 'Cs.' command + * \param addr The address of the string + * @return string at requested address + */ + QString getMetaString(RVA addr); /** * @brief Gets string at address * That function calls the 'ps' command diff --git a/src/dialogs/EditVariablesDialog.cpp b/src/dialogs/EditVariablesDialog.cpp index 5525048f..6954814a 100644 --- a/src/dialogs/EditVariablesDialog.cpp +++ b/src/dialogs/EditVariablesDialog.cpp @@ -73,7 +73,7 @@ void EditVariablesDialog::applyFields() if (!v_type || error_msg) { return; } - rz_analysis_var_set_type(v, v_type); + rz_analysis_var_set_type(v, v_type, true); // TODO Remove all those replace once rizin command parser is fixed QString newName = ui->nameEdit->text() diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 420d15bc..2c7b8ba8 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -533,7 +533,7 @@ void DisassemblyContextMenu::aboutToShowSlot() actionAnalyzeFunction.setVisible(true); // Show the option to remove a defined string only if a string is defined in this address - QString stringDefinition = Core()->cmdRawAt("Cs.", offset); + QString stringDefinition = Core()->getMetaString(offset); actionSetAsStringRemove.setVisible(!stringDefinition.isEmpty()); QString comment = Core()->getCommentAt(offset); diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index 760a7487..c494e5a0 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -599,10 +599,9 @@ void FunctionsWidget::onActionFunctionsRenameTriggered() void FunctionsWidget::onActionFunctionsUndefineTriggered() { const auto selection = ui->treeView->selectionModel()->selection().indexes(); - std::vector offsets; - offsets.reserve(selection.size()); + QSet offsets; for (const auto &index : selection) { - offsets.push_back(functionProxyModel->address(index)); + offsets.insert(functionProxyModel->address(index)); } for (RVA offset : offsets) { Core()->delFunction(offset); From 84d4a64f47b26759680c9d5c914f1f4f30f10cf9 Mon Sep 17 00:00:00 2001 From: Segev Finer Date: Sat, 5 Feb 2022 08:51:36 +0200 Subject: [PATCH 074/240] Enable console redirection on Windows without starting from a console (#2888) --- src/Main.cpp | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/Main.cpp b/src/Main.cpp index 89101b11..b0cef4a0 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -12,15 +12,11 @@ /** * @brief Attempt to connect to a parent console and configure outputs. - * - * @note Doesn't do anything if the exe wasn't executed from a console. */ #ifdef Q_OS_WIN static void connectToConsole() { - if (!AttachConsole(ATTACH_PARENT_PROCESS)) { - return; - } + BOOL attached = AttachConsole(ATTACH_PARENT_PROCESS); // Avoid reconfiguring stdin/stderr/stdout if one of them is already connected to a stream. // This can happen when running with stdout/stderr redirected to a file. @@ -32,12 +28,12 @@ static void connectToConsole() // _open() after startup. _close(0); - freopen("CONIN$", "r+", stdin); + freopen(attached ? "CONIN$" : "NUL", "r+", stdin); } if (0 > fileno(stdout)) { _close(1); - if (freopen("CONOUT$", "a+", stdout)) { + if (freopen(attached ? "CONOUT$" : "NUL", "a+", stdout)) { // Avoid buffering stdout/stderr since IOLBF is replaced by IOFBF in Win32. setvbuf(stdout, nullptr, _IONBF, 0); } @@ -45,7 +41,7 @@ static void connectToConsole() if (0 > fileno(stderr)) { _close(2); - if (freopen("CONOUT$", "a+", stderr)) { + if (freopen(attached ? "CONOUT$" : "NUL", "a+", stderr)) { setvbuf(stderr, nullptr, _IONBF, 0); } } From 2b50e2722b549e1ae8b1346feeb78a7725b53d3f Mon Sep 17 00:00:00 2001 From: Petros S Date: Sat, 5 Feb 2022 08:55:10 +0200 Subject: [PATCH 075/240] Move more common disassembly-previewing functionality to namaspace (#2849) --- src/common/DisassemblyPreview.cpp | 15 +++++-- src/common/DisassemblyPreview.h | 7 +++ src/widgets/DisassemblerGraphView.cpp | 10 ----- src/widgets/DisassemblerGraphView.h | 1 - src/widgets/DisassemblyWidget.cpp | 64 ++++----------------------- src/widgets/DisassemblyWidget.h | 1 - src/widgets/FunctionsWidget.cpp | 8 +--- 7 files changed, 28 insertions(+), 78 deletions(-) diff --git a/src/common/DisassemblyPreview.cpp b/src/common/DisassemblyPreview.cpp index df6fb58b..e80e6eaa 100644 --- a/src/common/DisassemblyPreview.cpp +++ b/src/common/DisassemblyPreview.cpp @@ -35,9 +35,6 @@ QString DisassemblyPreview::getToolTipStyleSheet() bool DisassemblyPreview::showDisasPreview(QWidget *parent, const QPoint &pointOfEvent, const RVA offsetFrom) { - QProcessEnvironment env; - QPoint point = pointOfEvent; - QList refs = Core()->getXRefs(offsetFrom, false, false); if (refs.length()) { if (refs.length() > 1) { @@ -75,10 +72,20 @@ bool DisassemblyPreview::showDisasPreview(QWidget *parent, const QPoint &pointOf .arg(qMax(8, fnt.pointSize() - 1)) .arg(disasmPreview.join("
")); - QToolTip::showText(point, tooltip, parent, QRect {}, 3500); + QToolTip::showText(pointOfEvent, tooltip, parent, QRect {}, 3500); return true; } } } return false; } + +RVA DisassemblyPreview::readDisassemblyOffset(QTextCursor tc) +{ + auto userData = getUserData(tc.block()); + if (!userData) { + return RVA_INVALID; + } + + return userData->line.offset; +} diff --git a/src/common/DisassemblyPreview.h b/src/common/DisassemblyPreview.h index 656b818e..81e67ee8 100644 --- a/src/common/DisassemblyPreview.h +++ b/src/common/DisassemblyPreview.h @@ -31,8 +31,15 @@ QString getToolTipStyleSheet(); /*! * @brief Show a QToolTip that previews the disassembly that is pointed to + * It works for GraphWidget and DisassemblyWidget * @return True if the tooltip is shown */ bool showDisasPreview(QWidget *parent, const QPoint &pointOfEvent, const RVA offsetFrom); + +/*! + * @brief Reads the offset for the cursor position + * @return The disassembly offset of the hovered asm text + */ +RVA readDisassemblyOffset(QTextCursor tc); } #endif diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index 7f434ff6..e4bb05b8 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -997,13 +997,3 @@ bool DisassemblerGraphView::Instr::contains(ut64 addr) const { return this->addr <= addr && (addr - this->addr) < size; } - -RVA DisassemblerGraphView::readDisassemblyOffset(QTextCursor tc) -{ - auto userData = getUserData(tc.block()); - if (!userData) { - return RVA_INVALID; - } - - return userData->line.offset; -} diff --git a/src/widgets/DisassemblerGraphView.h b/src/widgets/DisassemblerGraphView.h index 07bfc9ed..c5f10bb1 100644 --- a/src/widgets/DisassemblerGraphView.h +++ b/src/widgets/DisassemblerGraphView.h @@ -178,7 +178,6 @@ private: DisassemblyBlock *blockForAddress(RVA addr); void seekLocal(RVA addr, bool update_viewport = true); void seekInstruction(bool previous_instr); - RVA readDisassemblyOffset(QTextCursor tc); CutterSeekable *seekable = nullptr; QList shortcuts; diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index 97c83e64..be8c9bc9 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -371,7 +371,7 @@ void DisassemblyWidget::highlightCurrentLine() highlightSelection.cursor = cursor; highlightSelection.cursor.movePosition(QTextCursor::Start); while (true) { - RVA lineOffset = readDisassemblyOffset(highlightSelection.cursor); + RVA lineOffset = DisassemblyPreview::readDisassemblyOffset(highlightSelection.cursor); if (lineOffset == seekable->getOffset()) { highlightSelection.format.setBackground(highlightColor); highlightSelection.format.setProperty(QTextFormat::FullWidthSelection, true); @@ -406,7 +406,7 @@ void DisassemblyWidget::highlightPCLine() highlightSelection.cursor.movePosition(QTextCursor::Start); if (PCAddr != RVA_INVALID) { while (true) { - RVA lineOffset = readDisassemblyOffset(highlightSelection.cursor); + RVA lineOffset = DisassemblyPreview::readDisassemblyOffset(highlightSelection.cursor); if (lineOffset == PCAddr) { highlightSelection.format.setBackground(highlightPCColor); highlightSelection.format.setProperty(QTextFormat::FullWidthSelection, true); @@ -439,17 +439,7 @@ void DisassemblyWidget::showDisasContextMenu(const QPoint &pt) RVA DisassemblyWidget::readCurrentDisassemblyOffset() { QTextCursor tc = mDisasTextEdit->textCursor(); - return readDisassemblyOffset(tc); -} - -RVA DisassemblyWidget::readDisassemblyOffset(QTextCursor tc) -{ - auto userData = getUserData(tc.block()); - if (!userData) { - return RVA_INVALID; - } - - return userData->line.offset; + return DisassemblyPreview::readDisassemblyOffset(tc); } void DisassemblyWidget::updateCursorPosition() @@ -476,7 +466,7 @@ void DisassemblyWidget::updateCursorPosition() cursor.movePosition(QTextCursor::Start); while (true) { - RVA lineOffset = readDisassemblyOffset(cursor); + RVA lineOffset = DisassemblyPreview::readDisassemblyOffset(cursor); if (lineOffset == offset) { if (cursorLineOffset > 0) { cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, @@ -537,7 +527,7 @@ void DisassemblyWidget::cursorPositionChanged() cursorCharOffset = c.positionInBlock(); while (c.blockNumber() > 0) { c.movePosition(QTextCursor::PreviousBlock); - if (readDisassemblyOffset(c) != offset) { + if (DisassemblyPreview::readDisassemblyOffset(c) != offset) { break; } cursorLineOffset++; @@ -623,7 +613,7 @@ void DisassemblyWidget::moveCursorRelative(bool up, bool page) void DisassemblyWidget::jumpToOffsetUnderCursor(const QTextCursor &cursor) { - RVA offset = readDisassemblyOffset(cursor); + RVA offset = DisassemblyPreview::readDisassemblyOffset(cursor); seekable->seekToReference(offset); } @@ -645,47 +635,9 @@ bool DisassemblyWidget::eventFilter(QObject *obj, QEvent *event) auto cursorForWord = mDisasTextEdit->cursorForPosition(helpEvent->pos()); cursorForWord.select(QTextCursor::WordUnderCursor); - RVA offsetFrom = readDisassemblyOffset(cursorForWord); - RVA offsetTo = RVA_INVALID; + RVA offsetFrom = DisassemblyPreview::readDisassemblyOffset(cursorForWord); - QList refs = Core()->getXRefs(offsetFrom, false, false); - - if (refs.length()) { - if (refs.length() > 1) { - qWarning() << tr("More than one (%1) references here. Weird behaviour expected.") - .arg(refs.length()); - } - offsetTo = refs.at(0).to; // This is the offset we want to preview - - if (Q_UNLIKELY(offsetFrom != refs.at(0).from)) { - qWarning() << tr("offsetFrom (%1) differs from refs.at(0).from (%(2))") - .arg(offsetFrom) - .arg(refs.at(0).from); - } - - // Only if the offset we point *to* is different from the one the cursor is currently - // on *and* the former is a valid offset, we are allowed to get a preview of offsetTo - if (offsetTo != offsetFrom && offsetTo != RVA_INVALID) { - QStringList disasmPreview = Core()->getDisassemblyPreview(offsetTo, 10); - - // Last check to make sure the returned preview isn't an empty text (QStringList) - if (!disasmPreview.isEmpty()) { - const QFont &fnt = Config()->getFont(); - QFontMetrics fm { fnt }; - - QString tooltip = - QString("
Disassembly Preview:
%3
") - .arg(fnt.family()) - .arg(qMax(6, fnt.pointSize() - 1)) - .arg(disasmPreview.join("
")); - QToolTip::showText(helpEvent->globalPos(), tooltip, this, QRect(), 3500); - } - } - } - - return true; + return DisassemblyPreview::showDisasPreview(this, helpEvent->globalPos(), offsetFrom); } return MemoryDockWidget::eventFilter(obj, event); diff --git a/src/widgets/DisassemblyWidget.h b/src/widgets/DisassemblyWidget.h index 7657401d..1ab16216 100644 --- a/src/widgets/DisassemblyWidget.h +++ b/src/widgets/DisassemblyWidget.h @@ -83,7 +83,6 @@ private: RefreshDeferrer *disasmRefresh; RVA readCurrentDisassemblyOffset(); - RVA readDisassemblyOffset(QTextCursor tc); bool eventFilter(QObject *obj, QEvent *event) override; void keyPressEvent(QKeyEvent *event) override; QString getWindowTitle() const override; diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index c494e5a0..47c93aed 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -2,6 +2,7 @@ #include "ui_ListDockWidget.h" #include "core/MainWindow.h" +#include "common/DisassemblyPreview.h" #include "common/Helpers.h" #include "common/FunctionsTask.h" #include "common/TempConfig.h" @@ -634,10 +635,5 @@ void FunctionsWidget::onActionVerticalToggled(bool enable) */ void FunctionsWidget::setTooltipStylesheet() { - setStyleSheet(QString("QToolTip { border-width: 1px; max-width: %1px;" - "opacity: 230; background-color: %2;" - "color: %3; border-color: %3;}") - .arg(kMaxTooltipWidth) - .arg(Config()->getColor("gui.tooltip.background").name()) - .arg(Config()->getColor("gui.tooltip.foreground").name())); + setStyleSheet(DisassemblyPreview::getToolTipStyleSheet()); } From 2dbf136de8cf20353d49d87b328f190fd68edfb0 Mon Sep 17 00:00:00 2001 From: Theofilos Pechlivanis <49034471+theopechli@users.noreply.github.com> Date: Sat, 5 Feb 2022 09:00:08 +0200 Subject: [PATCH 076/240] Save and load the layout of the Functions widget (#2844) --- src/common/Configuration.cpp | 46 +++++++++++++++++++++------------ src/common/Configuration.h | 13 ++++++++++ src/widgets/FunctionsWidget.cpp | 8 +++++- 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 87a97b92..cc8690b4 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -21,17 +21,16 @@ * and for light - only light ones. */ const QHash Configuration::relevantThemes = { - { "ayu", DarkFlag }, { "basic", DarkFlag }, { "behelit", DarkFlag }, - { "bold", DarkFlag }, { "bright", DarkFlag }, { "consonance", DarkFlag }, - { "darkda", DarkFlag }, { "defragger", DarkFlag }, { "focus", DarkFlag }, - { "gentoo", DarkFlag }, { "lima", DarkFlag }, { "monokai", DarkFlag }, - { "ogray", DarkFlag }, { "onedark", DarkFlag }, { "pink", DarkFlag }, - { "rasta", DarkFlag }, { "sepia", DarkFlag }, { "smyck", DarkFlag }, - { "solarized", DarkFlag }, { "twilight", DarkFlag }, { "white2", DarkFlag }, - { "xvilka", DarkFlag }, { "zenburn", DarkFlag }, - { "cga", LightFlag }, { "cutter", LightFlag }, { "dark", LightFlag }, - { "gb", LightFlag }, { "matrix", LightFlag }, { "tango", LightFlag }, - { "white", LightFlag } + { "ayu", DarkFlag }, { "basic", DarkFlag }, { "behelit", DarkFlag }, + { "bold", DarkFlag }, { "bright", DarkFlag }, { "consonance", DarkFlag }, + { "darkda", DarkFlag }, { "defragger", DarkFlag }, { "focus", DarkFlag }, + { "gentoo", DarkFlag }, { "lima", DarkFlag }, { "monokai", DarkFlag }, + { "ogray", DarkFlag }, { "onedark", DarkFlag }, { "pink", DarkFlag }, + { "rasta", DarkFlag }, { "sepia", DarkFlag }, { "smyck", DarkFlag }, + { "solarized", DarkFlag }, { "twilight", DarkFlag }, { "white2", DarkFlag }, + { "xvilka", DarkFlag }, { "zenburn", DarkFlag }, { "cga", LightFlag }, + { "cutter", LightFlag }, { "dark", LightFlag }, { "gb", LightFlag }, + { "matrix", LightFlag }, { "tango", LightFlag }, { "white", LightFlag } }; static const QString DEFAULT_LIGHT_COLOR_THEME = "cutter"; static const QString DEFAULT_DARK_COLOR_THEME = "ayu"; @@ -251,8 +250,8 @@ bool Configuration::setLocaleByName(const QString &language) QLocale::matchingLocales(QLocale::AnyLanguage, QLocale::AnyScript, QLocale::AnyCountry); for (auto &it : allLocales) { - if (QString::compare(it.nativeLanguageName(), language, Qt::CaseInsensitive) == 0 || - it.name() == language) { + if (QString::compare(it.nativeLanguageName(), language, Qt::CaseInsensitive) == 0 + || it.name() == language) { setLocale(it); return true; } @@ -289,7 +288,8 @@ void Configuration::loadNativeStylesheet() QTextStream ts(&f); QString stylesheet = ts.readAll(); #ifdef Q_OS_MACOS - QFile mf(nativeWindowIsDark() ? ":native/native-macos-dark.qss" : ":native/native-macos-light.qss"); + QFile mf(nativeWindowIsDark() ? ":native/native-macos-dark.qss" + : ":native/native-macos-light.qss"); if (mf.exists()) { mf.open(QFile::ReadOnly | QFile::Text); QTextStream mts(&mf); @@ -667,11 +667,13 @@ QStringList Configuration::getAvailableTranslations() for (auto i : fileNames) { QString localeName = i.mid(sizeof("cutter_") - 1, 2); // TODO:#2321 don't asume 2 characters - // language code is sometimes 3 characters, and there could also be language_COUNTRY. Qt supports that. + // language code is sometimes 3 characters, and there could also be language_COUNTRY. Qt + // supports that. QLocale locale(localeName); if (locale.language() != QLocale::C) { currLanguageName = locale.nativeLanguageName(); - if (currLanguageName.isEmpty()) { // Qt doesn't have native language name for some languages + if (currLanguageName + .isEmpty()) { // Qt doesn't have native language name for some languages currLanguageName = QLocale::languageToString(locale.language()); } if (!currLanguageName.isEmpty()) { @@ -774,7 +776,7 @@ bool Configuration::getOutputRedirectionEnabled() const return outputRedirectEnabled; } -void Configuration::setPreviewValue( bool checked ) +void Configuration::setPreviewValue(bool checked) { s.setValue("asm.preview", checked); } @@ -821,3 +823,13 @@ void Configuration::addRecentProject(QString file) files.prepend(file); setRecentProjects(files); } + +QString Configuration::getFunctionsWidgetLayout() +{ + return s.value("functionsWidgetLayout").toString(); +} + +void Configuration::setFunctionsWidgetLayout(const QString &layout) +{ + s.setValue("functionsWidgetLayout", layout); +} diff --git a/src/common/Configuration.h b/src/common/Configuration.h index 3343e271..b6324705 100644 --- a/src/common/Configuration.h +++ b/src/common/Configuration.h @@ -228,6 +228,19 @@ public: void setRecentProjects(const QStringList &list); void addRecentProject(QString file); + // Functions Widget Layout + + /** + * @brief Get the layout of the Functions widget. + * @return The layout. + */ + QString getFunctionsWidgetLayout(); + + /** + * @brief Set the layout of the Functions widget + * @param layout The layout of the Functions widget, either horizontal or vertical. + */ + void setFunctionsWidgetLayout(const QString &layout); public slots: void refreshFont(); signals: diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index 47c93aed..f77bae3d 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -526,7 +526,11 @@ FunctionsWidget::FunctionsWidget(MainWindow *main) addActions(itemConextMenu->actions()); // Use a custom context menu on the dock title bar - actionHorizontal.setChecked(true); + if (Config()->getFunctionsWidgetLayout() == "horizontal") { + actionHorizontal.setChecked(true); + } else { + actionVertical.setChecked(true); + } this->setContextMenuPolicy(Qt::CustomContextMenu); connect(this, &QWidget::customContextMenuRequested, this, &FunctionsWidget::showTitleContextMenu); @@ -617,6 +621,7 @@ void FunctionsWidget::showTitleContextMenu(const QPoint &pt) void FunctionsWidget::onActionHorizontalToggled(bool enable) { if (enable) { + Config()->setFunctionsWidgetLayout("horizontal"); functionModel->setNested(false); ui->treeView->setIndentation(8); } @@ -625,6 +630,7 @@ void FunctionsWidget::onActionHorizontalToggled(bool enable) void FunctionsWidget::onActionVerticalToggled(bool enable) { if (enable) { + Config()->setFunctionsWidgetLayout("vertical"); functionModel->setNested(true); ui->treeView->setIndentation(20); } From f762b93e654041d3b6c15840d4e80249e10e5da9 Mon Sep 17 00:00:00 2001 From: Yossi Zap Date: Tue, 8 Feb 2022 23:22:55 +0200 Subject: [PATCH 077/240] Add missing rz_demangler.dll to windows packaging --- cmake/BundledRizin.cmake | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index ba6813e3..10f582b4 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -48,7 +48,8 @@ endif() set (RZ_LIBS rz_core rz_config rz_cons rz_io rz_util rz_flag rz_asm rz_debug rz_hash rz_bin rz_lang rz_il rz_analysis rz_parse rz_bp rz_egg rz_reg - rz_search rz_syscall rz_socket rz_magic rz_crypto rz_type rz_diff rz_sign) + rz_search rz_syscall rz_socket rz_magic rz_crypto rz_type rz_diff rz_sign + rz_demangler) set (RZ_EXTRA_LIBS rz_main) set (RZ_BIN rz-agent rz-bin rizin rz-diff rz-find rz-gg rz-hash rz-run rz-asm rz-ax) From 1b271a0ae8799f99c84c336a88d8c24729e4de63 Mon Sep 17 00:00:00 2001 From: Yossi Zap Date: Wed, 9 Feb 2022 16:04:04 +0200 Subject: [PATCH 078/240] Bypass meson Popen_safe_legacy() error --- .github/workflows/ccpp.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index e567c6b9..39b07cbe 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -70,6 +70,7 @@ jobs: brew install pkg-config - name: py dependencies run: | + python3 -m pip install -U pip==21.3.1 pip install meson - name: Prepare package id shell: bash From d65a352b1d51bb8b54b4c85f312ae1f990dbf92d Mon Sep 17 00:00:00 2001 From: yossizap Date: Sat, 19 Feb 2022 15:34:08 +0000 Subject: [PATCH 079/240] Remove additional 0x prefix in the registers widget (#2896) --- src/widgets/RegistersWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/RegistersWidget.cpp b/src/widgets/RegistersWidget.cpp index b6354fd3..ad9482e1 100644 --- a/src/widgets/RegistersWidget.cpp +++ b/src/widgets/RegistersWidget.cpp @@ -51,7 +51,7 @@ void RegistersWidget::setRegisterGrid() registerLen = registerRefs.size(); for (auto ® : registerRefs) { - regValue = "0x" + reg.value; + regValue = reg.value; // check if we already filled this grid space with label/value if (!registerLayout->itemAtPosition(i, col)) { registerLabel = new QLabel; From d34349b49ffc2bd785fae02f878de7fe8364eacf Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Mon, 14 Mar 2022 17:04:49 +0900 Subject: [PATCH 080/240] Use rizin instead of Qt to parse JSON (#2902) Qt truncates integers to 52-bit, corrupting e.g. memory addresses. Use rizin's JSON parser, which can parse integers whose size is up to 64 bits. --- .../code/development-guidelines.rst | 2 +- src/CMakeLists.txt | 2 + src/common/BugReporting.cpp | 10 +- src/common/ColorThemeWorker.cpp | 31 +- src/common/ColorThemeWorker.h | 1 + src/common/Decompiler.cpp | 21 +- src/common/IOModesController.cpp | 5 +- src/common/RizinTask.cpp | 8 +- src/common/RizinTask.h | 2 +- src/common/SettingsUpgrade.cpp | 2 +- src/core/Cutter.cpp | 519 +++++++----------- src/core/Cutter.h | 64 ++- src/core/CutterJson.cpp | 28 + src/core/CutterJson.h | 119 ++++ src/dialogs/VersionInfoDialog.cpp | 61 +- src/menus/DisassemblyContextMenu.cpp | 45 +- src/widgets/BacktraceWidget.cpp | 10 +- src/widgets/CallGraph.cpp | 10 +- src/widgets/ColorThemeListView.h | 1 + src/widgets/Dashboard.cpp | 45 +- src/widgets/Dashboard.h | 3 +- src/widgets/DisassemblerGraphView.cpp | 54 +- src/widgets/FunctionsWidget.cpp | 2 +- src/widgets/ProcessesWidget.cpp | 15 +- src/widgets/RegisterRefsWidget.cpp | 9 +- src/widgets/RizinGraphWidget.cpp | 13 +- src/widgets/StackWidget.cpp | 10 +- src/widgets/ThreadsWidget.cpp | 11 +- 28 files changed, 575 insertions(+), 528 deletions(-) create mode 100644 src/core/CutterJson.cpp create mode 100644 src/core/CutterJson.h diff --git a/docs/source/contributing/code/development-guidelines.rst b/docs/source/contributing/code/development-guidelines.rst index 948d134f..25560bfe 100644 --- a/docs/source/contributing/code/development-guidelines.rst +++ b/docs/source/contributing/code/development-guidelines.rst @@ -47,7 +47,7 @@ Example: .. code:: cpp - QJsonArray array = Core()->cmdj("pdj 1 @ main").array(); + CutterJson array = Core()->cmdj("pdj 1 @ main"); Seek the Current File ~~~~~~~~~~~~~~~~~~~~~ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index eb556529..4601cb96 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -4,6 +4,7 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/CutterConfig.h.in" set(SOURCES Main.cpp core/Cutter.cpp + core/CutterJson.cpp dialogs/EditStringDialog.cpp dialogs/WriteCommandsDialogs.cpp widgets/DisassemblerGraphView.cpp @@ -153,6 +154,7 @@ set(HEADER_FILES core/Cutter.h core/CutterCommon.h core/CutterDescriptions.h + core/CutterJson.h dialogs/EditStringDialog.h dialogs/WriteCommandsDialogs.h widgets/DisassemblerGraphView.h diff --git a/src/common/BugReporting.cpp b/src/common/BugReporting.cpp index f2242900..7d5ec919 100644 --- a/src/common/BugReporting.cpp +++ b/src/common/BugReporting.cpp @@ -12,13 +12,13 @@ void openIssue() // Pull in info needed for git issue osInfo = QSysInfo::productType() + " " + (QSysInfo::productVersion() == "unknown" ? "" : QSysInfo::productVersion()); - QJsonDocument docu = Core()->getFileInfo(); - QJsonObject coreObj = docu.object()["core"].toObject(); - QJsonObject binObj = docu.object()["bin"].toObject(); - if (!binObj.QJsonObject::isEmpty()) { + CutterJson docu = Core()->getFileInfo(); + CutterJson coreObj = docu["core"]; + CutterJson binObj = docu["bin"]; + if (binObj.size()) { format = coreObj["format"].toString(); arch = binObj["arch"].toString(); - if (!binObj["type"].isUndefined()) { + if (binObj["type"].valid()) { type = coreObj["type"].toString(); } else { type = "N/A"; diff --git a/src/common/ColorThemeWorker.cpp b/src/common/ColorThemeWorker.cpp index a7ca2bc8..aabc0c1f 100644 --- a/src/common/ColorThemeWorker.cpp +++ b/src/common/ColorThemeWorker.cpp @@ -128,22 +128,34 @@ bool ColorThemeWorker::isThemeExist(const QString &name) const QJsonDocument ColorThemeWorker::getTheme(const QString &themeName) const { int r, g, b, a; + CutterJson rzTheme; QVariantMap theme; QString curr = Config()->getColorTheme(); if (themeName != curr) { RzCoreLocked core(Core()); rz_core_theme_load(core, themeName.toUtf8().constData()); - theme = Core()->cmdj("ecj").object().toVariantMap(); + rzTheme = Core()->cmdj("ecj"); rz_core_theme_load(core, curr.toUtf8().constData()); } else { - theme = Core()->cmdj("ecj").object().toVariantMap(); + rzTheme = Core()->cmdj("ecj"); } - for (auto it = theme.begin(); it != theme.end(); it++) { - auto arr = it.value().toList(); - QColor(arr[0].toInt(), arr[1].toInt(), arr[2].toInt()).getRgb(&r, &g, &b, &a); - theme[it.key()] = QJsonArray({ r, g, b, a }); + for (CutterJson value : rzTheme) { + QJsonArray arr; + int count = 0; + for (CutterJson element : value) { + arr.append(element.toSt64()); + count++; + if (count >= 3) { + break; + } + } + while (count < 3) { + arr.append(0); + } + arr.append(255); + theme[value.key()] = arr; } ColorFlags colorFlags = ColorFlags::DarkFlag; @@ -278,9 +290,8 @@ bool ColorThemeWorker::isFileTheme(const QString &filePath, bool *ok) const } const QString colors = "black|red|white|green|magenta|yellow|cyan|blue|gray|none"; - QString options = (Core()->cmdj("ecj").object().keys() << cutterSpecificOptions) - .join('|') - .replace(".", "\\."); + QString options = + (Core()->cmdj("ecj").keys() << cutterSpecificOptions).join('|').replace(".", "\\."); QString pattern = QString("((ec\\s+(%1)\\s+(((rgb:|#)[0-9a-fA-F]{3,8})|(%2))))\\s*") .arg(options) @@ -315,7 +326,7 @@ QStringList ColorThemeWorker::customThemes() const const QStringList &ColorThemeWorker::getRizinSpecificOptions() { if (rizinSpecificOptions.isEmpty()) { - rizinSpecificOptions = Core()->cmdj("ecj").object().keys(); + rizinSpecificOptions = Core()->cmdj("ecj").keys(); } return rizinSpecificOptions; } diff --git a/src/common/ColorThemeWorker.h b/src/common/ColorThemeWorker.h index 7c228804..3d67826f 100644 --- a/src/common/ColorThemeWorker.h +++ b/src/common/ColorThemeWorker.h @@ -5,6 +5,7 @@ #include #include #include "Cutter.h" +#include #include #define ThemeWorker() (ColorThemeWorker::instance()) diff --git a/src/common/Decompiler.cpp b/src/common/Decompiler.cpp index 569a7d68..94892075 100644 --- a/src/common/Decompiler.cpp +++ b/src/common/Decompiler.cpp @@ -33,40 +33,37 @@ void JSDecDecompiler::decompileAt(RVA addr) } task = new RizinCmdTask("pddj @ " + QString::number(addr)); connect(task, &RizinCmdTask::finished, this, [this]() { - QJsonObject json = task->getResultJson().object(); + CutterJson json = task->getResultJson(); delete task; task = nullptr; - if (json.isEmpty()) { + if (!json.size()) { emit finished(Decompiler::makeWarning(tr("Failed to parse JSON from jsdec"))); return; } RzAnnotatedCode *code = rz_annotated_code_new(nullptr); QString codeString = ""; - for (const auto &line : json["log"].toArray()) { - if (!line.isString()) { + for (auto line : json["log"]) { + if (line.type() != RZ_JSON_STRING) { continue; } codeString.append(line.toString() + "\n"); } - auto linesArray = json["lines"].toArray(); - for (const auto &line : linesArray) { - QJsonObject lineObject = line.toObject(); - if (lineObject.isEmpty()) { + for (auto lineObject : json["lines"]) { + if (!lineObject.size()) { continue; } RzCodeAnnotation annotationi = {}; annotationi.start = codeString.length(); codeString.append(lineObject["str"].toString() + "\n"); annotationi.end = codeString.length(); - bool ok; annotationi.type = RZ_CODE_ANNOTATION_TYPE_OFFSET; - annotationi.offset.offset = lineObject["offset"].toVariant().toULongLong(&ok); + annotationi.offset.offset = lineObject["offset"].toUt64(); rz_annotated_code_add_annotation(code, &annotationi); } - for (const auto &line : json["errors"].toArray()) { - if (!line.isString()) { + for (auto line : json["errors"]) { + if (line.type() != RZ_JSON_STRING) { continue; } codeString.append(line.toString() + "\n"); diff --git a/src/common/IOModesController.cpp b/src/common/IOModesController.cpp index e7a11aaf..4fa29502 100644 --- a/src/common/IOModesController.cpp +++ b/src/common/IOModesController.cpp @@ -78,11 +78,10 @@ bool IOModesController::prepareForWriting() bool IOModesController::allChangesComitted() { // Get a list of available write changes - QJsonArray changes = Core()->cmdj("wcj").array(); + CutterJson changes = Core()->cmdj("wcj"); // Check if there is a change which isn't written to the file - for (const QJsonValue &value : changes) { - QJsonObject changeObject = value.toObject(); + for (CutterJson changeObject : changes) { if (!changeObject["written"].toBool()) { return false; } diff --git a/src/common/RizinTask.cpp b/src/common/RizinTask.cpp index 48cb0901..14433585 100644 --- a/src/common/RizinTask.cpp +++ b/src/common/RizinTask.cpp @@ -54,13 +54,15 @@ QString RizinCmdTask::getResult() return QString::fromUtf8(res); } -QJsonDocument RizinCmdTask::getResultJson() +CutterJson RizinCmdTask::getResultJson() { const char *res = rz_core_cmd_task_get_result(task); if (!res) { - return QJsonDocument(); + return CutterJson(); } - return Core()->parseJson(res, nullptr); + char *copy = static_cast(rz_mem_alloc(strlen(res) + 1)); + strcpy(copy, res); + return Core()->parseJson(copy, nullptr); } const char *RizinCmdTask::getResultRaw() diff --git a/src/common/RizinTask.h b/src/common/RizinTask.h index e07e1fb3..e0972bc4 100644 --- a/src/common/RizinTask.h +++ b/src/common/RizinTask.h @@ -38,7 +38,7 @@ public: explicit RizinCmdTask(const QString &cmd, bool transient = true); QString getResult(); - QJsonDocument getResultJson(); + CutterJson getResultJson(); const char *getResultRaw(); }; diff --git a/src/common/SettingsUpgrade.cpp b/src/common/SettingsUpgrade.cpp index 9ff48999..4ef57e59 100644 --- a/src/common/SettingsUpgrade.cpp +++ b/src/common/SettingsUpgrade.cpp @@ -181,7 +181,7 @@ void Cutter::initializeSettings() static void removeObsoleteOptionsFromCustomThemes() { - const QStringList options = Core()->cmdj("ecj").object().keys() + const QStringList options = Core()->cmdj("ecj").keys() << ColorThemeWorker::cutterSpecificOptions; RzList *themes_list = rz_core_theme_list(Core()->core()); RzListIter *th_iter; diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 21a07c57..bb0b661a 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -481,7 +481,7 @@ QString CutterCore::cmdRaw(const char *cmd) return res; } -QJsonDocument CutterCore::cmdj(const char *str) +CutterJson CutterCore::cmdj(const char *str) { char *res; { @@ -489,15 +489,12 @@ QJsonDocument CutterCore::cmdj(const char *str) res = rz_core_cmd_str(core, str); } - QJsonDocument doc = parseJson(res, str); - rz_mem_free(res); - - return doc; + return parseJson(res, str); } -QJsonDocument CutterCore::cmdjAt(const char *str, RVA address) +CutterJson CutterCore::cmdjAt(const char *str, RVA address) { - QJsonDocument res; + CutterJson res; RVA oldOffset = getOffset(); seekSilent(address); @@ -515,49 +512,42 @@ QString CutterCore::cmdTask(const QString &str) return task.getResult(); } -QJsonDocument CutterCore::cmdjTask(const QString &str) +CutterJson CutterCore::cmdjTask(const QString &str) { RizinCmdTask task(str); task.startTask(); task.joinTask(); - return parseJson(task.getResultRaw(), str); + const char *res = task.getResultRaw(); + char *copy = static_cast(rz_mem_alloc(strlen(res) + 1)); + strcpy(copy, res); + return parseJson(copy, str); } -QJsonDocument CutterCore::parseJson(const char *res, const char *cmd) +CutterJson CutterCore::parseJson(char *res, const char *cmd) { - QByteArray json(res); - - if (json.isEmpty()) { - return QJsonDocument(); + if (!res) { + return CutterJson(); } - QJsonParseError jsonError; - QJsonDocument doc = QJsonDocument::fromJson(json, &jsonError); + RzJson *doc = rz_json_parse(res); - if (jsonError.error != QJsonParseError::NoError) { - // don't call trimmed() before knowing that parsing failed to avoid copying huge jsons all - // the time - if (json.trimmed().isEmpty()) { - return doc; - } + if (!doc) { if (cmd) { - eprintf("Failed to parse JSON for command \"%s\": %s\n", cmd, - jsonError.errorString().toLocal8Bit().constData()); + eprintf("Failed to parse JSON for command \"%s\"\n", cmd); } else { - eprintf("Failed to parse JSON: %s\n", - jsonError.errorString().toLocal8Bit().constData()); + eprintf("Failed to parse JSON\n"); } const int MAX_JSON_DUMP_SIZE = 8 * 1024; - if (json.length() > MAX_JSON_DUMP_SIZE) { - int originalSize = json.length(); - json.resize(MAX_JSON_DUMP_SIZE); - eprintf("%d bytes total: %s ...\n", originalSize, json.constData()); + size_t originalSize = strlen(res); + if (originalSize > MAX_JSON_DUMP_SIZE) { + res[MAX_JSON_DUMP_SIZE] = 0; + eprintf("%zu bytes total: %s ...\n", originalSize, res); } else { - eprintf("%s\n", json.constData()); + eprintf("%s\n", res); } } - return doc; + return CutterJson(doc, QSharedPointer::create(doc, res)); } QStringList CutterCore::autocomplete(const QString &cmd, RzLinePromptType promptType, size_t limit) @@ -675,8 +665,7 @@ bool CutterCore::mapFile(QString path, RVA mapaddr) { CORE_LOCK(); RVA addr = mapaddr != RVA_INVALID ? mapaddr : 0; - ut64 baddr = - Core()->getFileInfo().object()["bin"].toObject()["baddr"].toVariant().toULongLong(); + ut64 baddr = Core()->getFileInfo()["bin"]["baddr"].toUt64(); if (rz_core_file_open(core, path.toUtf8().constData(), RZ_PERM_RX, addr)) { rz_core_bin_load(core, path.toUtf8().constData(), baddr); } else { @@ -737,20 +726,12 @@ void CutterCore::delFlag(const QString &name) QString CutterCore::getInstructionBytes(RVA addr) { - return cmdj("aoj @ " + RzAddressString(addr)) - .array() - .first() - .toObject()[RJsonKey::bytes] - .toString(); + return cmdj("aoj @ " + RzAddressString(addr)).first()[RJsonKey::bytes].toString(); } QString CutterCore::getInstructionOpcode(RVA addr) { - return cmdj("aoj @ " + RzAddressString(addr)) - .array() - .first() - .toObject()[RJsonKey::opcode] - .toString(); + return cmdj("aoj @ " + RzAddressString(addr)).first()[RJsonKey::opcode].toString(); } void CutterCore::editInstruction(RVA addr, const QString &inst) @@ -1010,21 +991,19 @@ RVA CutterCore::nextOpAddr(RVA startAddr, int count) { CORE_LOCK(); - QJsonArray array = - Core()->cmdj("pdj " + QString::number(count + 1) + " @ " + QString::number(startAddr)) - .array(); - if (array.isEmpty()) { + CutterJson array = + Core()->cmdj("pdj " + QString::number(count + 1) + " @ " + QString::number(startAddr)); + if (!array.size()) { return startAddr + 1; } - QJsonValue instValue = array.last(); - if (!instValue.isObject()) { + CutterJson instValue = array.last(); + if (instValue.type() != RZ_JSON_OBJECT) { return startAddr + 1; } - bool ok; - RVA offset = instValue.toObject()[RJsonKey::offset].toVariant().toULongLong(&ok); - if (!ok) { + RVA offset = instValue[RJsonKey::offset].toRVA(); + if (offset == RVA_INVALID) { return startAddr + 1; } @@ -1340,27 +1319,14 @@ void CutterCore::createFunctionAt(RVA addr, QString name) emit functionsChanged(); } -QJsonDocument CutterCore::getRegistersInfo() +CutterJson CutterCore::getRegistersInfo() { return cmdj("aeafj"); } RVA CutterCore::getOffsetJump(RVA addr) { - bool ok; - RVA value = cmdj("aoj @" + QString::number(addr)) - .array() - .first() - .toObject() - .value(RJsonKey::jump) - .toVariant() - .toULongLong(&ok); - - if (!ok) { - return RVA_INVALID; - } - - return value; + return cmdj("aoj @" + QString::number(addr)).first().toRVA(); } QList CutterCore::getDecompilers() @@ -1388,17 +1354,17 @@ bool CutterCore::registerDecompiler(Decompiler *decompiler) return true; } -QJsonDocument CutterCore::getFileInfo() +CutterJson CutterCore::getFileInfo() { return cmdj("ij"); } -QJsonDocument CutterCore::getFileVersionInfo() +CutterJson CutterCore::getFileVersionInfo() { return cmdj("iVj"); } -QJsonDocument CutterCore::getSignatureInfo() +CutterJson CutterCore::getSignatureInfo() { return cmdj("iCj"); } @@ -1413,41 +1379,43 @@ static inline const QString appendVar(QString &dst, const QString val, const QSt return val; } -RefDescription CutterCore::formatRefDesc(QJsonObject refItem) +RefDescription CutterCore::formatRefDesc(const AddrRefs &refItem) { RefDescription desc; - // Ignore empty refs and refs that only contain addr - if (refItem.size() <= 1) { + if (refItem.addr == RVA_INVALID) { return desc; } - QString str = refItem["string"].toVariant().toString(); + QString str = refItem.string; if (!str.isEmpty()) { desc.ref = str; desc.refColor = ConfigColor("comment"); } else { + QSharedPointer cursor(&refItem); QString type, string; - do { + while (true) { desc.ref += " ->"; - appendVar(desc.ref, refItem["reg"].toVariant().toString(), " @", ""); - appendVar(desc.ref, refItem["mapname"].toVariant().toString(), " (", ")"); - appendVar(desc.ref, refItem["section"].toVariant().toString(), " (", ")"); - appendVar(desc.ref, refItem["func"].toVariant().toString(), " ", ""); - type = appendVar(desc.ref, refItem["type"].toVariant().toString(), " ", ""); - appendVar(desc.ref, refItem["perms"].toVariant().toString(), " ", ""); - appendVar(desc.ref, refItem["asm"].toVariant().toString(), " \"", "\""); - string = appendVar(desc.ref, refItem["string"].toVariant().toString(), " ", ""); + appendVar(desc.ref, cursor->reg, " @", ""); + appendVar(desc.ref, cursor->mapname, " (", ")"); + appendVar(desc.ref, cursor->section, " (", ")"); + appendVar(desc.ref, cursor->fcn, " ", ""); + type = appendVar(desc.ref, cursor->type, " ", ""); + appendVar(desc.ref, cursor->perms, " ", ""); + appendVar(desc.ref, cursor->asm_op, " \"", "\""); + string = appendVar(desc.ref, cursor->string, " ", ""); if (!string.isNull()) { // There is no point in adding ascii and addr info after a string break; } - if (!refItem["value"].isNull()) { - appendVar(desc.ref, RzAddressString(refItem["value"].toVariant().toULongLong()), - " ", ""); + if (cursor->has_value) { + appendVar(desc.ref, RzAddressString(cursor->value), " ", ""); } - refItem = refItem["ref"].toObject(); - } while (!refItem.empty()); + if (!cursor->ref) { + break; + } + cursor = cursor->ref; + } // Set the ref's color according to the last item type if (type == "ascii" || !string.isEmpty()) { @@ -1464,29 +1432,28 @@ RefDescription CutterCore::formatRefDesc(QJsonObject refItem) return desc; } -QList CutterCore::getRegisterRefs(int depth) +QList CutterCore::getRegisterRefs(int depth) { - QList ret; + QList ret; if (!currentlyDebugging) { return ret; } - QJsonObject registers = cmdj("drj").object(); - - for (const QString &key : registers.keys()) { - QJsonObject reg; - reg["value"] = registers.value(key); - reg["ref"] = getAddrRefs(registers.value(key).toVariant().toULongLong(), depth); - reg["name"] = key; + CutterJson registers = cmdj("drj"); + for (CutterJson value : registers) { + RegisterRef reg; + reg.value = value.toUt64(); + reg.ref = getAddrRefs(reg.value, depth); + reg.name = value.key(); ret.append(reg); } return ret; } -QList CutterCore::getStack(int size, int depth) +QList CutterCore::getStack(int size, int depth) { - QList stack; + QList stack; if (!currentlyDebugging) { return stack; } @@ -1510,11 +1477,12 @@ QList CutterCore::getStack(int size, int depth) return stack; } -QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) +AddrRefs CutterCore::getAddrRefs(RVA addr, int depth) { - QJsonObject json; + AddrRefs refs; if (depth < 1 || addr == UT64_MAX) { - return json; + refs.addr = RVA_INVALID; + return refs; } CORE_LOCK(); @@ -1522,19 +1490,19 @@ QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) QByteArray buf = QByteArray(); ut64 type = rz_core_analysis_address(core, addr); - json["addr"] = QString::number(addr); + refs.addr = addr; // Search for the section the addr is in, avoid duplication for heap/stack with type if (!(type & RZ_ANALYSIS_ADDR_TYPE_HEAP || type & RZ_ANALYSIS_ADDR_TYPE_STACK)) { // Attempt to find the address within a map RzDebugMap *map = rz_debug_map_get(core->dbg, addr); if (map && map->name && map->name[0]) { - json["mapname"] = map->name; + refs.mapname = map->name; } RzBinSection *sect = rz_bin_get_section_at(rz_bin_cur_object(core->bin), addr, true); if (sect && sect->name[0]) { - json["section"] = sect->name; + refs.section = sect->name; } } @@ -1543,30 +1511,30 @@ QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) if (fi) { RzRegItem *r = rz_reg_get(core->dbg->reg, fi->name, -1); if (r) { - json["reg"] = r->name; + refs.reg = r->name; } } // Attempt to find the address within a function RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, addr, 0); if (fcn) { - json["fcn"] = fcn->name; + refs.fcn = fcn->name; } // Update type and permission information if (type != 0) { if (type & RZ_ANALYSIS_ADDR_TYPE_HEAP) { - json["type"] = "heap"; + refs.type = "heap"; } else if (type & RZ_ANALYSIS_ADDR_TYPE_STACK) { - json["type"] = "stack"; + refs.type = "stack"; } else if (type & RZ_ANALYSIS_ADDR_TYPE_PROGRAM) { - json["type"] = "program"; + refs.type = "program"; } else if (type & RZ_ANALYSIS_ADDR_TYPE_LIBRARY) { - json["type"] = "library"; + refs.type = "library"; } else if (type & RZ_ANALYSIS_ADDR_TYPE_ASCII) { - json["type"] = "ascii"; + refs.type = "ascii"; } else if (type & RZ_ANALYSIS_ADDR_TYPE_SEQUENCE) { - json["type"] = "sequence"; + refs.type = "sequence"; } QString perms = ""; @@ -1584,11 +1552,11 @@ QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) rz_io_read_at(core->io, addr, (unsigned char *)buf.data(), buf.size()); rz_asm_set_pc(core->rasm, addr); rz_asm_disassemble(core->rasm, &op, (unsigned char *)buf.data(), buf.size()); - json["asm"] = rz_asm_op_get_asm(&op); + refs.asm_op = rz_asm_op_get_asm(&op); } if (!perms.isEmpty()) { - json["perms"] = perms; + refs.perms = perms; } } @@ -1601,14 +1569,15 @@ QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) ut64 n = (bits == 64) ? *n64 : *n32; // The value of the next address will serve as an indication that there's more to // telescope if we have reached the depth limit - json["value"] = QString::number(n); + refs.value = n; + refs.has_value = true; if (depth && n != addr && !(type & RZ_ANALYSIS_ADDR_TYPE_EXEC)) { // Make sure we aren't telescoping the same address - QJsonObject ref = getAddrRefs(n, depth - 1); - if (!ref.empty() && !ref["type"].isNull()) { + AddrRefs ref = getAddrRefs(n, depth - 1); + if (!ref.type.isNull()) { // If the dereference of the current pointer is an ascii character we // might have a string in this address - if (ref["type"].toString().contains("ascii")) { + if (ref.type.contains("ascii")) { buf.resize(128); rz_io_read_at(core->io, addr, (unsigned char *)buf.data(), buf.size()); QString strVal = QString(buf); @@ -1616,16 +1585,16 @@ QJsonObject CutterCore::getAddrRefs(RVA addr, int depth) if (strVal.size() == buf.size()) { strVal += "..."; } - json["string"] = strVal; + refs.string = strVal; } - json["ref"] = ref; + refs.ref = QSharedPointer::create(ref); } } } - return json; + return refs; } -QJsonDocument CutterCore::getProcessThreads(int pid) +CutterJson CutterCore::getProcessThreads(int pid) { if (-1 == pid) { // Return threads list of the currently debugged PID @@ -1765,7 +1734,7 @@ bool CutterCore::writeHeapChunk(RzHeapChunkSimple *chunk_simple) return rz_heap_write_chunk(core, chunk_simple); } -QJsonDocument CutterCore::getChildProcesses(int pid) +CutterJson CutterCore::getChildProcesses(int pid) { // Return the currently debugged process and it's children if (-1 == pid) { @@ -1775,7 +1744,7 @@ QJsonDocument CutterCore::getChildProcesses(int pid) return cmdj("dpj " + QString::number(pid)); } -QJsonDocument CutterCore::getRegisterValues() +CutterJson CutterCore::getRegisterValues() { return cmdj("drj"); } @@ -1783,11 +1752,10 @@ QJsonDocument CutterCore::getRegisterValues() QList CutterCore::getVariables(RVA at) { QList ret; - QJsonObject varsObject = cmdj(QString("afvj @ %1").arg(at)).object(); + CutterJson varsObject = cmdj(QString("afvj @ %1").arg(at)); - auto addVars = [&](VariableDescription::RefType refType, const QJsonArray &array) { - for (const QJsonValue &varValue : array) { - QJsonObject varObject = varValue.toObject(); + auto addVars = [&](VariableDescription::RefType refType, const CutterJson &array) { + for (CutterJson varObject : array) { VariableDescription desc; desc.refType = refType; desc.name = varObject["name"].toString(); @@ -1796,21 +1764,19 @@ QList CutterCore::getVariables(RVA at) } }; - addVars(VariableDescription::RefType::SP, varsObject["sp"].toArray()); - addVars(VariableDescription::RefType::BP, varsObject["bp"].toArray()); - addVars(VariableDescription::RefType::Reg, varsObject["reg"].toArray()); + addVars(VariableDescription::RefType::SP, varsObject["sp"]); + addVars(VariableDescription::RefType::BP, varsObject["bp"]); + addVars(VariableDescription::RefType::Reg, varsObject["reg"]); return ret; } QVector CutterCore::getRegisterRefValues() { - QJsonArray registerRefArray = cmdj("drrj").array(); + CutterJson registerRefArray = cmdj("drrj"); QVector result; - for (const QJsonValue value : registerRefArray) { - QJsonObject regRefObject = value.toObject(); - + for (CutterJson regRefObject : registerRefArray) { RegisterRefValueDescription desc; desc.name = regRefObject[RJsonKey::reg].toString(); desc.value = regRefObject[RJsonKey::value].toString(); @@ -2371,11 +2337,8 @@ void CutterCore::stepBackDebug() QStringList CutterCore::getDebugPlugins() { QStringList plugins; - QJsonArray pluginArray = cmdj("dLj").array(); - - for (const QJsonValue &value : pluginArray) { - QJsonObject pluginObject = value.toObject(); + for (CutterJson pluginObject : cmdj("dLj")) { QString plugin = pluginObject[RJsonKey::name].toString(); plugins << plugin; @@ -2647,7 +2610,7 @@ bool CutterCore::isBreakpoint(const QList &breakpoints, RVA addr) return breakpoints.contains(addr); } -QJsonDocument CutterCore::getBacktrace() +CutterJson CutterCore::getBacktrace() { return cmdj("dbtj"); } @@ -2655,15 +2618,12 @@ QJsonDocument CutterCore::getBacktrace() QList CutterCore::getAllProcesses() { QList ret; - QJsonArray processArray = cmdj("dplj").array(); - - for (const QJsonValue &value : processArray) { - QJsonObject procObject = value.toObject(); + for (CutterJson procObject : cmdj("dplj")) { ProcessDescription proc; - proc.pid = procObject[RJsonKey::pid].toInt(); - proc.uid = procObject[RJsonKey::uid].toInt(); + proc.pid = procObject[RJsonKey::pid].toSt64(); + proc.uid = procObject[RJsonKey::uid].toSt64(); proc.status = procObject[RJsonKey::status].toString(); proc.path = procObject[RJsonKey::path].toString(); @@ -2676,17 +2636,14 @@ QList CutterCore::getAllProcesses() QList CutterCore::getMemoryMap() { QList ret; - QJsonArray memoryMapArray = cmdj("dmj").array(); - - for (const QJsonValue &value : memoryMapArray) { - QJsonObject memMapObject = value.toObject(); + for (CutterJson memMapObject : cmdj("dmj")) { MemoryMapDescription memMap; memMap.name = memMapObject[RJsonKey::name].toString(); memMap.fileName = memMapObject[RJsonKey::file].toString(); - memMap.addrStart = memMapObject[RJsonKey::addr].toVariant().toULongLong(); - memMap.addrEnd = memMapObject[RJsonKey::addr_end].toVariant().toULongLong(); + memMap.addrStart = memMapObject[RJsonKey::addr].toRVA(); + memMap.addrEnd = memMapObject[RJsonKey::addr_end].toRVA(); memMap.type = memMapObject[RJsonKey::type].toString(); memMap.permission = memMapObject[RJsonKey::perm].toString(); @@ -2925,15 +2882,11 @@ QList CutterCore::getAllImports() CORE_LOCK(); QList ret; - QJsonArray importsArray = cmdj("iij").array(); - - for (const QJsonValue &value : importsArray) { - QJsonObject importObject = value.toObject(); - + for (CutterJson importObject : cmdj("iij")) { ImportDescription import; - import.plt = importObject[RJsonKey::plt].toVariant().toULongLong(); - import.ordinal = importObject[RJsonKey::ordinal].toInt(); + import.plt = importObject[RJsonKey::plt].toRVA(); + import.ordinal = importObject[RJsonKey::ordinal].toSt64(); import.bind = importObject[RJsonKey::bind].toString(); import.type = importObject[RJsonKey::type].toString(); import.libname = importObject[RJsonKey::libname].toString(); @@ -2950,16 +2903,12 @@ QList CutterCore::getAllExports() CORE_LOCK(); QList ret; - QJsonArray exportsArray = cmdj("iEj").array(); - - for (const QJsonValue &value : exportsArray) { - QJsonObject exportObject = value.toObject(); - + for (CutterJson exportObject : cmdj("iEj")) { ExportDescription exp; - exp.vaddr = exportObject[RJsonKey::vaddr].toVariant().toULongLong(); - exp.paddr = exportObject[RJsonKey::paddr].toVariant().toULongLong(); - exp.size = exportObject[RJsonKey::size].toVariant().toULongLong(); + exp.vaddr = exportObject[RJsonKey::vaddr].toRVA(); + exp.paddr = exportObject[RJsonKey::paddr].toRVA(); + exp.size = exportObject[RJsonKey::size].toRVA(); exp.type = exportObject[RJsonKey::type].toString(); exp.name = exportObject[RJsonKey::name].toString(); exp.flag_name = exportObject[RJsonKey::flagname].toString(); @@ -3010,15 +2959,11 @@ QList CutterCore::getAllHeaders() CORE_LOCK(); QList ret; - QJsonArray headersArray = cmdj("ihj").array(); - - for (const QJsonValue &value : headersArray) { - QJsonObject headerObject = value.toObject(); - + for (CutterJson headerObject : cmdj("ihj")) { HeaderDescription header; - header.vaddr = headerObject[RJsonKey::vaddr].toVariant().toULongLong(); - header.paddr = headerObject[RJsonKey::paddr].toVariant().toULongLong(); + header.vaddr = headerObject[RJsonKey::vaddr].toRVA(); + header.paddr = headerObject[RJsonKey::paddr].toRVA(); header.value = headerObject[RJsonKey::comment].toString(); header.name = headerObject[RJsonKey::name].toString(); @@ -3063,16 +3008,13 @@ QList CutterCore::getAllComments(const QString &filterType) CORE_LOCK(); QList ret; - QJsonArray commentsArray = cmdj("CClj").array(); - for (const QJsonValue &value : commentsArray) { - QJsonObject commentObject = value.toObject(); - + for (CutterJson commentObject : cmdj("CClj")) { QString type = commentObject[RJsonKey::type].toString(); if (type != filterType) continue; CommentDescription comment; - comment.offset = commentObject[RJsonKey::offset].toVariant().toULongLong(); + comment.offset = commentObject[RJsonKey::offset].toRVA(); comment.name = commentObject[RJsonKey::name].toString(); ret << comment; @@ -3114,22 +3056,19 @@ QList CutterCore::getAllStrings() return parseStringsJson(cmdjTask("izzj")); } -QList CutterCore::parseStringsJson(const QJsonDocument &doc) +QList CutterCore::parseStringsJson(const CutterJson &doc) { QList ret; - QJsonArray stringsArray = doc.array(); - for (const QJsonValue &value : stringsArray) { - QJsonObject stringObject = value.toObject(); - + for (CutterJson value : doc) { StringDescription string; - string.string = stringObject[RJsonKey::string].toString(); - string.vaddr = stringObject[RJsonKey::vaddr].toVariant().toULongLong(); - string.type = stringObject[RJsonKey::type].toString(); - string.size = stringObject[RJsonKey::size].toVariant().toUInt(); - string.length = stringObject[RJsonKey::length].toVariant().toUInt(); - string.section = stringObject[RJsonKey::section].toString(); + string.string = value[RJsonKey::string].toString(); + string.vaddr = value[RJsonKey::vaddr].toRVA(); + string.type = value[RJsonKey::type].toString(); + string.size = value[RJsonKey::size].toUt64(); + string.length = value[RJsonKey::length].toUt64(); + string.section = value[RJsonKey::section].toString(); ret << string; } @@ -3249,21 +3188,17 @@ QList CutterCore::getAllSegments() CORE_LOCK(); QList ret; - QJsonArray segments = cmdj("iSSj").array(); - - for (const QJsonValue &value : segments) { - QJsonObject segmentObject = value.toObject(); - + for (CutterJson segmentObject : cmdj("iSSj")) { QString name = segmentObject[RJsonKey::name].toString(); if (name.isEmpty()) continue; SegmentDescription segment; segment.name = name; - segment.vaddr = segmentObject[RJsonKey::vaddr].toVariant().toULongLong(); - segment.paddr = segmentObject[RJsonKey::paddr].toVariant().toULongLong(); - segment.size = segmentObject[RJsonKey::size].toVariant().toULongLong(); - segment.vsize = segmentObject[RJsonKey::vsize].toVariant().toULongLong(); + segment.vaddr = segmentObject[RJsonKey::vaddr].toRVA(); + segment.paddr = segmentObject[RJsonKey::paddr].toRVA(); + segment.size = segmentObject[RJsonKey::size].toRVA(); + segment.vsize = segmentObject[RJsonKey::vsize].toRVA(); segment.perm = segmentObject[RJsonKey::perm].toString(); ret << segment; @@ -3276,17 +3211,14 @@ QList CutterCore::getAllEntrypoint() CORE_LOCK(); QList ret; - QJsonArray entrypointsArray = cmdj("iej").array(); - for (const QJsonValue &value : entrypointsArray) { - QJsonObject entrypointObject = value.toObject(); - + for (CutterJson entrypointObject : cmdj("iej")) { EntrypointDescription entrypoint; - entrypoint.vaddr = entrypointObject[RJsonKey::vaddr].toVariant().toULongLong(); - entrypoint.paddr = entrypointObject[RJsonKey::paddr].toVariant().toULongLong(); - entrypoint.baddr = entrypointObject[RJsonKey::baddr].toVariant().toULongLong(); - entrypoint.laddr = entrypointObject[RJsonKey::laddr].toVariant().toULongLong(); - entrypoint.haddr = entrypointObject[RJsonKey::haddr].toVariant().toULongLong(); + entrypoint.vaddr = entrypointObject[RJsonKey::vaddr].toRVA(); + entrypoint.paddr = entrypointObject[RJsonKey::paddr].toRVA(); + entrypoint.baddr = entrypointObject[RJsonKey::baddr].toRVA(); + entrypoint.laddr = entrypointObject[RJsonKey::laddr].toRVA(); + entrypoint.haddr = entrypointObject[RJsonKey::haddr].toRVA(); entrypoint.type = entrypointObject[RJsonKey::type].toString(); ret << entrypoint; @@ -3299,34 +3231,27 @@ QList CutterCore::getAllClassesFromBin() CORE_LOCK(); QList ret; - QJsonArray classesArray = cmdj("icj").array(); - for (const QJsonValue &value : classesArray) { - QJsonObject classObject = value.toObject(); - + for (CutterJson classObject : cmdj("icj")) { BinClassDescription cls; cls.name = classObject[RJsonKey::classname].toString(); - cls.addr = classObject[RJsonKey::addr].toVariant().toULongLong(); - cls.index = classObject[RJsonKey::index].toVariant().toULongLong(); - - for (const QJsonValue &value2 : classObject[RJsonKey::methods].toArray()) { - QJsonObject methObject = value2.toObject(); + cls.addr = classObject[RJsonKey::addr].toRVA(); + cls.index = classObject[RJsonKey::index].toUt64(); + for (CutterJson methObject : classObject[RJsonKey::methods]) { BinClassMethodDescription meth; meth.name = methObject[RJsonKey::name].toString(); - meth.addr = methObject[RJsonKey::addr].toVariant().toULongLong(); + meth.addr = methObject[RJsonKey::addr].toRVA(); cls.methods << meth; } - for (const QJsonValue &value2 : classObject[RJsonKey::fields].toArray()) { - QJsonObject fieldObject = value2.toObject(); - + for (CutterJson fieldObject : classObject[RJsonKey::fields]) { BinClassFieldDescription field; field.name = fieldObject[RJsonKey::name].toString(); - field.addr = fieldObject[RJsonKey::addr].toVariant().toULongLong(); + field.addr = fieldObject[RJsonKey::addr].toRVA(); cls.fields << field; } @@ -3345,10 +3270,7 @@ QList CutterCore::getAllClassesFromFlags() QList ret; QMap classesCache; - QJsonArray flagsArray = cmdj("fj@F:classes").array(); - for (const QJsonValue &value : flagsArray) { - QJsonObject flagObject = value.toObject(); - + for (const CutterJson flagObject : cmdj("fj@F:classes")) { QString flagName = flagObject[RJsonKey::name].toString(); QRegularExpressionMatch match = classFlagRegExp.match(flagName); @@ -3365,7 +3287,7 @@ QList CutterCore::getAllClassesFromFlags() desc = it.value(); } desc->name = match.captured(1); - desc->addr = flagObject[RJsonKey::offset].toVariant().toULongLong(); + desc->addr = flagObject[RJsonKey::offset].toRVA(); desc->index = RVA_INVALID; continue; } @@ -3390,7 +3312,7 @@ QList CutterCore::getAllClassesFromFlags() BinClassMethodDescription meth; meth.name = match.captured(2); - meth.addr = flagObject[RJsonKey::offset].toVariant().toULongLong(); + meth.addr = flagObject[RJsonKey::offset].toRVA(); classDesc->methods << meth; continue; } @@ -3559,17 +3481,14 @@ QList CutterCore::getAllResources() CORE_LOCK(); QList resources; - QJsonArray resourcesArray = cmdj("iRj").array(); - for (const QJsonValue &value : resourcesArray) { - QJsonObject resourceObject = value.toObject(); - + for (CutterJson resourceObject : cmdj("iRj")) { ResourcesDescription res; res.name = resourceObject[RJsonKey::name].toString(); - res.vaddr = resourceObject[RJsonKey::vaddr].toVariant().toULongLong(); - res.index = resourceObject[RJsonKey::index].toVariant().toULongLong(); + res.vaddr = resourceObject[RJsonKey::vaddr].toRVA(); + res.index = resourceObject[RJsonKey::index].toUt64(); res.type = resourceObject[RJsonKey::type].toString(); - res.size = resourceObject[RJsonKey::size].toVariant().toULongLong(); + res.size = resourceObject[RJsonKey::size].toUt64(); res.lang = resourceObject[RJsonKey::lang].toString(); resources << res; @@ -3582,21 +3501,15 @@ QList CutterCore::getAllVTables() CORE_LOCK(); QList vtables; - QJsonArray vTablesArray = cmdj("avj").array(); - for (const QJsonValue &vTableValue : vTablesArray) { - QJsonObject vTableObject = vTableValue.toObject(); - + for (CutterJson vTableObject : cmdj("avj")) { VTableDescription res; - res.addr = vTableObject[RJsonKey::offset].toVariant().toULongLong(); - QJsonArray methodArray = vTableObject[RJsonKey::methods].toArray(); - - for (const QJsonValue &methodValue : methodArray) { - QJsonObject methodObject = methodValue.toObject(); + res.addr = vTableObject[RJsonKey::offset].toRVA(); + for (CutterJson methodObject : vTableObject[RJsonKey::methods]) { BinClassMethodDescription method; - method.addr = methodObject[RJsonKey::offset].toVariant().toULongLong(); + method.addr = methodObject[RJsonKey::offset].toRVA(); method.name = methodObject[RJsonKey::name].toString(); res.methods << method; @@ -3693,43 +3606,33 @@ QList CutterCore::getAllSearch(QString searchFor, QString spa CORE_LOCK(); QList searchRef; - QJsonArray searchArray; + CutterJson searchArray; { TempConfig cfg; cfg.set("search.in", in); - searchArray = cmdj(QString("%1 %2").arg(space, searchFor)).array(); + searchArray = cmdj(QString("%1 %2").arg(space, searchFor)); } if (space == "/Rj") { - for (const QJsonValue &value : searchArray) { - QJsonObject searchObject = value.toObject(); - + for (CutterJson searchObject : searchArray) { SearchDescription exp; exp.code.clear(); - for (const QJsonValue &value2 : searchObject[RJsonKey::opcodes].toArray()) { - QJsonObject gadget = value2.toObject(); + for (CutterJson gadget : searchObject[RJsonKey::opcodes]) { exp.code += gadget[RJsonKey::opcode].toString() + "; "; } - exp.offset = searchObject[RJsonKey::opcodes] - .toArray() - .first() - .toObject()[RJsonKey::offset] - .toVariant() - .toULongLong(); - exp.size = searchObject[RJsonKey::size].toVariant().toULongLong(); + exp.offset = searchObject[RJsonKey::opcodes].first()[RJsonKey::offset].toRVA(); + exp.size = searchObject[RJsonKey::size].toUt64(); searchRef << exp; } } else { - for (const QJsonValue &value : searchArray) { - QJsonObject searchObject = value.toObject(); - + for (CutterJson searchObject : searchArray) { SearchDescription exp; - exp.offset = searchObject[RJsonKey::offset].toVariant().toULongLong(); - exp.size = searchObject[RJsonKey::len].toVariant().toULongLong(); + exp.offset = searchObject[RJsonKey::offset].toRVA(); + exp.size = searchObject[RJsonKey::len].toUt64(); exp.code = searchObject[RJsonKey::code].toString(); exp.data = searchObject[RJsonKey::data].toString(); @@ -3747,35 +3650,31 @@ BlockStatistics CutterCore::getBlockStatistics(unsigned int blocksCount) return blockStats; } - QJsonObject statsObj; + CutterJson statsObj; // User TempConfig here to set the search boundaries to all sections. This makes sure // that the Visual Navbar will show all the relevant addresses. { TempConfig tempConfig; tempConfig.set("search.in", "bin.sections"); - statsObj = cmdj("p-j " + QString::number(blocksCount)).object(); + statsObj = cmdj("p-j " + QString::number(blocksCount)); } - blockStats.from = statsObj[RJsonKey::from].toVariant().toULongLong(); - blockStats.to = statsObj[RJsonKey::to].toVariant().toULongLong(); - blockStats.blocksize = statsObj[RJsonKey::blocksize].toVariant().toULongLong(); - - QJsonArray blocksArray = statsObj[RJsonKey::blocks].toArray(); - - for (const QJsonValue &value : blocksArray) { - QJsonObject blockObj = value.toObject(); + blockStats.from = statsObj[RJsonKey::from].toRVA(); + blockStats.to = statsObj[RJsonKey::to].toRVA(); + blockStats.blocksize = statsObj[RJsonKey::blocksize].toRVA(); + for (CutterJson blockObj : statsObj[RJsonKey::blocks]) { BlockDescription block; - block.addr = blockObj[RJsonKey::offset].toVariant().toULongLong(); - block.size = blockObj[RJsonKey::size].toVariant().toULongLong(); - block.flags = blockObj[RJsonKey::flags].toInt(0); - block.functions = blockObj[RJsonKey::functions].toInt(0); - block.inFunctions = blockObj[RJsonKey::in_functions].toInt(0); - block.comments = blockObj[RJsonKey::comments].toInt(0); - block.symbols = blockObj[RJsonKey::symbols].toInt(0); - block.strings = blockObj[RJsonKey::strings].toInt(0); + block.addr = blockObj[RJsonKey::offset].toRVA(); + block.size = blockObj[RJsonKey::size].toRVA(); + block.flags = blockObj[RJsonKey::flags].toSt64(); + block.functions = blockObj[RJsonKey::functions].toSt64(); + block.inFunctions = blockObj[RJsonKey::in_functions].toSt64(); + block.comments = blockObj[RJsonKey::comments].toSt64(); + block.symbols = blockObj[RJsonKey::symbols].toSt64(); + block.strings = blockObj[RJsonKey::strings].toSt64(); block.rwx = 0; QString rwxStr = blockObj[RJsonKey::rwx].toString(); @@ -3801,20 +3700,12 @@ QList CutterCore::getXRefsForVariable(QString variableName, boo RVA offset) { QList xrefList = QList(); - QJsonArray xrefsArray; - if (findWrites) { - xrefsArray = cmdjAt("afvWj", offset).array(); - } else { - xrefsArray = cmdjAt("afvRj", offset).array(); - } - for (const QJsonValue &value : xrefsArray) { - QJsonObject xrefObject = value.toObject(); + for (CutterJson xrefObject : cmdjAt(findWrites ? "afvWj" : "afvRj", offset)) { QString name = xrefObject[RJsonKey::name].toString(); if (name == variableName) { - QJsonArray addressArray = xrefObject[RJsonKey::addrs].toArray(); - for (const QJsonValue &address : addressArray) { + for (CutterJson address : xrefObject[RJsonKey::addrs]) { XrefDescription xref; - RVA addr = address.toVariant().toULongLong(); + RVA addr = address.toRVA(); xref.from = addr; xref.to = addr; if (findWrites) { @@ -3890,11 +3781,11 @@ QString CutterCore::listFlagsAsStringAt(RVA addr) QString CutterCore::nearestFlag(RVA offset, RVA *flagOffsetOut) { - auto r = cmdj(QString("fdj @ ") + QString::number(offset)).object(); - QString name = r.value("name").toString(); + auto r = cmdj(QString("fdj @ ") + QString::number(offset)); + QString name = r["name"].toString(); if (flagOffsetOut) { - auto offsetValue = r.value("offset"); - *flagOffsetOut = offsetValue.isUndefined() ? offset : offsetValue.toVariant().toULongLong(); + auto offsetValue = r["offset"]; + *flagOffsetOut = offsetValue.valid() ? offsetValue.toRVA() : offset; } return name; } @@ -3965,18 +3856,15 @@ void CutterCore::loadPDB(const QString &file) QList CutterCore::disassembleLines(RVA offset, int lines) { - QJsonArray array = cmdj(QString("pdJ ") + QString::number(lines) + QString(" @ ") - + QString::number(offset)) - .array(); + CutterJson array = cmdj(QString("pdJ ") + QString::number(lines) + QString(" @ ") + + QString::number(offset)); QList r; - for (const QJsonValueRef &value : array) { - QJsonObject object = value.toObject(); + for (CutterJson object : array) { DisassemblyLine line; - line.offset = object[RJsonKey::offset].toVariant().toULongLong(); + line.offset = object[RJsonKey::offset].toRVA(); line.text = ansiEscapeToHtml(object[RJsonKey::text].toString()); - const auto &arrow = object[RJsonKey::arrow]; - line.arrow = arrow.isNull() ? RVA_INVALID : arrow.toVariant().toULongLong(); + line.arrow = object[RJsonKey::arrow].toRVA(); r << line; } @@ -4094,8 +3982,7 @@ QString CutterCore::getVersionInformation() QList CutterCore::getColorThemes() { QList r; - QJsonDocument themes = cmdj("ecoj"); - for (const QJsonValue &s : themes.array()) { + for (CutterJson s : cmdj("ecoj")) { r << s.toString(); } return r; @@ -4181,13 +4068,13 @@ void CutterCore::setWriteMode(bool enabled) bool CutterCore::isWriteModeEnabled() { - using namespace std; - QJsonArray ans = cmdj("oj").array(); - return find_if(begin(ans), end(ans), - [](const QJsonValue &v) { return v.toObject().value("raised").toBool(); }) - ->toObject() - .value("writable") - .toBool(); + for (CutterJson v : cmdj("oj")) { + if (v["raised"].toBool()) { + return v["writable"].toBool(); + } + } + + return false; } /** diff --git a/src/core/Cutter.h b/src/core/Cutter.h index d8b7a0a1..c1e21e50 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -3,15 +3,16 @@ #include "core/CutterCommon.h" #include "core/CutterDescriptions.h" +#include "core/CutterJson.h" #include "common/BasicInstructionHighlighter.h" #include #include #include #include +#include #include #include -#include #include #include #include @@ -34,6 +35,29 @@ class RizinTaskDialog; class RzCoreLocked; +struct CUTTER_EXPORT AddrRefs +{ + RVA addr; + QString mapname; + QString section; + QString reg; + QString fcn; + QString type; + QString asm_op; + QString perms; + ut64 value; + bool has_value; + QString string; + QSharedPointer ref; +}; + +struct CUTTER_EXPORT RegisterRef +{ + ut64 value; + AddrRefs ref; + QString name; +}; + class CUTTER_EXPORT CutterCore : public QObject { Q_OBJECT @@ -124,16 +148,16 @@ public: seekSilent(oldOffset); } - QJsonDocument cmdj(const char *str); - QJsonDocument cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); } - QJsonDocument cmdjAt(const char *str, RVA address); + CutterJson cmdj(const char *str); + CutterJson cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); } + CutterJson cmdjAt(const char *str, RVA address); QStringList cmdList(const char *str) { return cmd(str).split(QLatin1Char('\n'), CUTTER_QT_SKIP_EMPTY_PARTS); } QStringList cmdList(const QString &str) { return cmdList(str.toUtf8().constData()); } QString cmdTask(const QString &str); - QJsonDocument cmdjTask(const QString &str); + CutterJson cmdjTask(const QString &str); /** * @brief send a command to Rizin and check for ESIL errors * @param command the command you want to execute @@ -159,8 +183,8 @@ public: QString getRizinVersionReadable(); QString getVersionInformation(); - QJsonDocument parseJson(const char *res, const char *cmd = nullptr); - QJsonDocument parseJson(const char *res, const QString &cmd = QString()) + CutterJson parseJson(char *res, const char *cmd = nullptr); + CutterJson parseJson(char *res, const QString &cmd = QString()) { return parseJson(res, cmd.isNull() ? nullptr : cmd.toLocal8Bit().constData()); } @@ -376,8 +400,8 @@ public: bool sdbSet(QString path, QString key, QString val); /* Debug */ - QJsonDocument getRegistersInfo(); - QJsonDocument getRegisterValues(); + CutterJson getRegistersInfo(); + CutterJson getRegisterValues(); QString getRegisterName(QString registerRole); RVA getProgramCounterValue(); void setRegister(QString regName, QString regValue); @@ -391,32 +415,32 @@ public: * @param size number of bytes to scan * @param depth telescoping depth */ - QList getStack(int size = 0x100, int depth = 6); + QList getStack(int size = 0x100, int depth = 6); /** * @brief Recursively dereferences pointers starting at the specified address * up to a given depth * @param addr telescoping addr * @param depth telescoping depth */ - QJsonObject getAddrRefs(RVA addr, int depth); + AddrRefs getAddrRefs(RVA addr, int depth); /** * @brief return a RefDescription with a formatted ref string and configured colors * @param ref the "ref" JSON node from getAddrRefs */ - RefDescription formatRefDesc(QJsonObject ref); + RefDescription formatRefDesc(const AddrRefs &ref); /** * @brief Get a list of a given process's threads * @param pid The pid of the process, -1 for the currently debugged process * @return JSON object result of dptj */ - QJsonDocument getProcessThreads(int pid); + CutterJson getProcessThreads(int pid); /** * @brief Get a list of a given process's child processes * @param pid The pid of the process, -1 for the currently debugged process * @return JSON object result of dptj */ - QJsonDocument getChildProcesses(int pid); - QJsonDocument getBacktrace(); + CutterJson getChildProcesses(int pid); + CutterJson getBacktrace(); /** * @brief Get a list of heap chunks * Uses RZ_API rz_heap_chunks_list to get vector of chunks @@ -532,9 +556,9 @@ public: bool registerDecompiler(Decompiler *decompiler); RVA getOffsetJump(RVA addr); - QJsonDocument getFileInfo(); - QJsonDocument getSignatureInfo(); - QJsonDocument getFileVersionInfo(); + CutterJson getFileInfo(); + CutterJson getSignatureInfo(); + CutterJson getFileVersionInfo(); QStringList getStats(); void setGraphEmpty(bool empty); bool isGraphEmpty(); @@ -631,7 +655,7 @@ public: * @brief returns a list of reg values and their telescoped references * @param depth telescoping depth */ - QList getRegisterRefs(int depth = 6); + QList getRegisterRefs(int depth = 6); QVector getRegisterRefValues(); QList getVariables(RVA at); /** @@ -649,7 +673,7 @@ public: QList getXRefs(RVA addr, bool to, bool whole_function, const QString &filterType = QString()); - QList parseStringsJson(const QJsonDocument &doc); + QList parseStringsJson(const CutterJson &doc); void handleREvent(int type, void *data); diff --git a/src/core/CutterJson.cpp b/src/core/CutterJson.cpp new file mode 100644 index 00000000..dc6667c0 --- /dev/null +++ b/src/core/CutterJson.cpp @@ -0,0 +1,28 @@ +#include "core/CutterJson.h" + +CutterJson CutterJson::last() const +{ + if (!has_children()) { + return CutterJson(); + } + + const RzJson *last = value->children.first; + while (last->next) { + last = last->next; + } + + return CutterJson(last, owner); +} + +QStringList CutterJson::keys() const +{ + QStringList list; + + if (value && value->type == RZ_JSON_OBJECT) { + for (const RzJson *child = value->children.first; child; child = child->next) { + list.append(child->key); + } + } + + return list; +} diff --git a/src/core/CutterJson.h b/src/core/CutterJson.h new file mode 100644 index 00000000..042ca84b --- /dev/null +++ b/src/core/CutterJson.h @@ -0,0 +1,119 @@ +#ifndef CUTTER_JSON_H +#define CUTTER_JSON_H + +#include "core/CutterCommon.h" + +#include +#include +#include +#include + +class CutterJsonOwner; + +class CUTTER_EXPORT CutterJson +{ +public: + class iterator + { + public: + iterator(const RzJson *value, QSharedPointer owner) + : value(value), owner(owner) + { + } + + CutterJson operator*() const { return CutterJson(value, owner); } + + bool operator!=(const iterator &other) const { return value != other.value; } + + iterator &operator++() + { + value = value->next; + return *this; + } + + private: + const RzJson *value; + QSharedPointer owner; + }; + + CutterJson() : value(nullptr), owner(nullptr) {} + + CutterJson(const RzJson *value, QSharedPointer owner) + : value(value), owner(owner) + { + } + + CutterJson first() const + { + return CutterJson(has_children() ? value->children.first : nullptr, owner); + } + + CutterJson last() const; + + CutterJson operator[](const QString &key) const + { + QByteArray utf8 = key.toUtf8(); + return (*this)[utf8.data()]; + } + + CutterJson operator[](const char *key) const + { + return CutterJson( + value && value->type == RZ_JSON_OBJECT ? rz_json_get(value, key) : nullptr, owner); + } + + iterator begin() const + { + return iterator(has_children() ? value->children.first : nullptr, owner); + } + + iterator end() const { return iterator(nullptr, nullptr); } + + bool toBool() const { return value && value->type == RZ_JSON_BOOLEAN && value->num.u_value; } + QString toJson() const { return rz_json_as_string(value); } + st64 toSt64() const { return value && value->type == RZ_JSON_INTEGER ? value->num.s_value : 0; } + ut64 toUt64() const { return value && value->type == RZ_JSON_INTEGER ? value->num.u_value : 0; } + + RVA toRVA() const + { + return value && value->type == RZ_JSON_INTEGER ? value->num.u_value : RVA_INVALID; + } + + QString toString() const + { + return value && value->type == RZ_JSON_STRING ? QString(value->str_value) : QString(); + } + + QString key() const { return value ? value->key : QString(); } + QStringList keys() const; + size_t size() const { return has_children() ? value->children.count : 0; } + RzJsonType type() const { return value ? value->type : RZ_JSON_NULL; } + bool valid() const { return value ? true : false; } + +private: + bool has_children() const + { + return value && (value->type == RZ_JSON_OBJECT || value->type == RZ_JSON_ARRAY); + } + + const RzJson *value; + QSharedPointer owner; +}; + +class CUTTER_EXPORT CutterJsonOwner +{ +public: + CutterJsonOwner(RzJson *value, char *text) : value(value), text(text) {} + + virtual ~CutterJsonOwner() + { + rz_json_free(value); + rz_mem_free(text); + } + +private: + RzJson *value; + char *text; +}; + +#endif // CUTTER_JSON_H diff --git a/src/dialogs/VersionInfoDialog.cpp b/src/dialogs/VersionInfoDialog.cpp index 9d166bb4..7e67d594 100644 --- a/src/dialogs/VersionInfoDialog.cpp +++ b/src/dialogs/VersionInfoDialog.cpp @@ -24,12 +24,12 @@ VersionInfoDialog::~VersionInfoDialog() {} void VersionInfoDialog::fillVersionInfo() { - QJsonDocument doc = Core()->getFileVersionInfo(); + CutterJson doc = Core()->getFileVersionInfo(); // Case ELF - if (doc.object().contains("verneed")) { - QJsonObject verneed = doc.object()["verneed"].toArray().first().toObject(); - QJsonObject versym = doc.object()["versym"].toArray().first().toObject(); + if (doc["verneed"].valid()) { + CutterJson verneed = doc["verneed"].first(); + CutterJson versym = doc["versym"].first(); // Set labels ui->leftLabel->setText("Version symbols"); @@ -43,17 +43,17 @@ void VersionInfoDialog::fillVersionInfo() QTreeWidgetItem *addrItemL = new QTreeWidgetItem(); addrItemL->setText(0, "Address:"); - addrItemL->setText(1, RzAddressString(versym["address"].toDouble())); + addrItemL->setText(1, RzAddressString(versym["address"].toRVA())); ui->leftTreeWidget->addTopLevelItem(addrItemL); QTreeWidgetItem *offItemL = new QTreeWidgetItem(); offItemL->setText(0, "Offset:"); - offItemL->setText(1, RzAddressString(versym["offset"].toDouble())); + offItemL->setText(1, RzAddressString(versym["offset"].toRVA())); ui->leftTreeWidget->addTopLevelItem(offItemL); QTreeWidgetItem *linkItemL = new QTreeWidgetItem(); linkItemL->setText(0, "Link:"); - linkItemL->setText(1, QString::number(versym["link"].toDouble())); + linkItemL->setText(1, QString::number(versym["link"].toRVA())); ui->leftTreeWidget->addTopLevelItem(linkItemL); QTreeWidgetItem *linkNameItemL = new QTreeWidgetItem(); @@ -63,10 +63,9 @@ void VersionInfoDialog::fillVersionInfo() QTreeWidgetItem *entriesItemL = new QTreeWidgetItem(); entriesItemL->setText(0, "Entries:"); - for (QJsonValue val : versym["entries"].toArray()) { - QJsonObject obj = val.toObject(); + for (CutterJson obj : versym["entries"]) { QTreeWidgetItem *tempItem = new QTreeWidgetItem(); - tempItem->setText(0, RzAddressString(obj["idx"].toDouble())); + tempItem->setText(0, RzAddressString(obj["idx"].toRVA())); tempItem->setText(1, obj["value"].toString()); entriesItemL->addChild(tempItem); } @@ -83,17 +82,17 @@ void VersionInfoDialog::fillVersionInfo() QTreeWidgetItem *addrItemR = new QTreeWidgetItem(); addrItemR->setText(0, "Address:"); - addrItemR->setText(1, RzAddressString(verneed["address"].toDouble())); + addrItemR->setText(1, RzAddressString(verneed["address"].toRVA())); ui->rightTreeWidget->addTopLevelItem(addrItemR); QTreeWidgetItem *offItemR = new QTreeWidgetItem(); offItemR->setText(0, "Offset:"); - offItemR->setText(1, RzAddressString(verneed["offset"].toDouble())); + offItemR->setText(1, RzAddressString(verneed["offset"].toRVA())); ui->rightTreeWidget->addTopLevelItem(offItemR); QTreeWidgetItem *linkItemR = new QTreeWidgetItem(); linkItemR->setText(0, "Link:"); - linkItemR->setText(1, QString::number(verneed["link"].toDouble())); + linkItemR->setText(1, QString::number(verneed["link"].toSt64())); ui->rightTreeWidget->addTopLevelItem(linkItemR); QTreeWidgetItem *linkNameItemR = new QTreeWidgetItem(); @@ -103,24 +102,22 @@ void VersionInfoDialog::fillVersionInfo() QTreeWidgetItem *entriesItemR = new QTreeWidgetItem(); entriesItemR->setText(0, "Entries:"); - for (QJsonValue parentVal : verneed["entries"].toArray()) { - QJsonObject parentObj = parentVal.toObject(); + for (CutterJson parentObj : verneed["entries"]) { QTreeWidgetItem *parentItem = new QTreeWidgetItem(); QString parentString; - parentItem->setText(0, RzAddressString(parentObj["idx"].toDouble())); - parentString.append("Version: " + QString::number(parentObj["vn_version"].toDouble()) + parentItem->setText(0, RzAddressString(parentObj["idx"].toRVA())); + parentString.append("Version: " + QString::number(parentObj["vn_version"].toSt64()) + "\t"); parentString.append("File: " + parentObj["file_name"].toString()); parentItem->setText(1, parentString); - for (QJsonValue childVal : parentObj["vernaux"].toArray()) { - QJsonObject childObj = childVal.toObject(); + for (CutterJson childObj : parentObj["vernaux"]) { QTreeWidgetItem *childItem = new QTreeWidgetItem(); QString childString; - childItem->setText(0, RzAddressString(childObj["idx"].toDouble())); + childItem->setText(0, RzAddressString(childObj["idx"].toRVA())); childString.append("Name: " + childObj["name"].toString() + "\t"); childString.append("Flags: " + childObj["flags"].toString() + "\t"); - childString.append("Version: " + QString::number(childObj["version"].toDouble())); + childString.append("Version: " + QString::number(childObj["version"].toSt64())); childItem->setText(1, childString); parentItem->addChild(childItem); } @@ -134,22 +131,22 @@ void VersionInfoDialog::fillVersionInfo() } // Case PE - else if (doc.object().contains("VS_FIXEDFILEINFO")) { - QJsonObject vs = doc.object()["VS_FIXEDFILEINFO"].toObject(); - QJsonObject strings = doc.object()["StringTable"].toObject(); + else if (doc["VS_FIXEDFILEINFO"].valid()) { + CutterJson vs = doc["VS_FIXEDFILEINFO"]; + CutterJson strings = doc["StringTable"]; // Set labels ui->leftLabel->setText("VS Fixed file info"); ui->rightLabel->setText("String table"); // Left tree - for (QString key : vs.keys()) { + for (CutterJson property : vs) { QTreeWidgetItem *tempItem = new QTreeWidgetItem(); - tempItem->setText(0, key); - if (vs[key].isDouble()) - tempItem->setText(1, RzHexString(vs[key].toDouble())); + tempItem->setText(0, property.key()); + if (property.type() == RZ_JSON_INTEGER) + tempItem->setText(1, RzHexString(property.toRVA())); else - tempItem->setText(1, vs[key].toString()); + tempItem->setText(1, property.toString()); ui->leftTreeWidget->addTopLevelItem(tempItem); // Adjust columns to content @@ -157,10 +154,10 @@ void VersionInfoDialog::fillVersionInfo() } // Right tree - for (QString key : strings.keys()) { + for (CutterJson property : strings) { QTreeWidgetItem *tempItem = new QTreeWidgetItem(); - tempItem->setText(0, key); - tempItem->setText(1, strings[key].toString()); + tempItem->setText(0, property.key()); + tempItem->setText(1, property.toString()); ui->rightTreeWidget->addTopLevelItem(tempItem); // Adjust columns to content diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 2c7b8ba8..c2065c9d 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -314,15 +314,15 @@ void DisassemblyContextMenu::addDebugMenu() QVector DisassemblyContextMenu::getThingUsedHere(RVA offset) { QVector result; - const QJsonArray array = Core()->cmdj("anj @ " + QString::number(offset)).array(); + const CutterJson array = Core()->cmdj("anj @ " + QString::number(offset)); result.reserve(array.size()); for (const auto &thing : array) { - auto obj = thing.toObject(); - RVA offset = obj["offset"].toVariant().toULongLong(); + auto obj = thing; + RVA offset = obj["offset"].toRVA(); QString name; // If real names display is enabled, show flag's real name instead of full flag name - if (Config()->getConfigBool("asm.flags.real") && obj.contains("realname")) { + if (Config()->getConfigBool("asm.flags.real") && obj["realname"].valid()) { name = obj["realname"].toString(); } else { name = obj["name"].toString(); @@ -482,29 +482,24 @@ void DisassemblyContextMenu::setupRenaming() void DisassemblyContextMenu::aboutToShowSlot() { // check if set immediate base menu makes sense - QJsonObject instObject = - Core()->cmdj("aoj @ " + QString::number(offset)).array().first().toObject(); - auto keys = instObject.keys(); - bool immBase = keys.contains("val") || keys.contains("ptr"); + CutterJson instObject = Core()->cmdj("aoj @ " + QString::number(offset)).first(); + bool immBase = instObject["val"].valid() || instObject["ptr"].valid(); setBaseMenu->menuAction()->setVisible(immBase); setBitsMenu->menuAction()->setVisible(true); // Create structure offset menu if it makes sense QString memBaseReg; // Base register - QVariant memDisp; // Displacement - if (instObject.contains("opex") && instObject["opex"].toObject().contains("operands")) { - // Loop through both the operands of the instruction - for (const QJsonValue value : instObject["opex"].toObject()["operands"].toArray()) { - QJsonObject operand = value.toObject(); - if (operand.contains("type") && operand["type"].toString() == "mem" - && operand.contains("base") && !operand["base"].toString().contains("bp") - && operand.contains("disp") && operand["disp"].toVariant().toLongLong() > 0) { + st64 memDisp; // Displacement - // The current operand is the one which has an immediate displacement - memBaseReg = operand["base"].toString(); - memDisp = operand["disp"].toVariant(); - break; - } + // Loop through both the operands of the instruction + for (const CutterJson operand : instObject["opex"]["operands"]) { + if (operand["type"].toString() == "mem" && !operand["base"].toString().contains("bp") + && operand["disp"].toSt64() > 0) { + + // The current operand is the one which has an immediate displacement + memBaseReg = operand["base"].toString(); + memDisp = operand["disp"].toSt64(); + break; } } if (memBaseReg.isEmpty()) { @@ -517,7 +512,7 @@ void DisassemblyContextMenu::aboutToShowSlot() // Get the possible offsets using the "ahts" command // TODO: add ahtj command to Rizin and then use it here - QStringList ret = Core()->cmdList("ahts " + memDisp.toString()); + QStringList ret = Core()->cmdList("ahts " + QString::number(memDisp)); for (const QString &val : ret) { if (val.isEmpty()) { continue; @@ -714,12 +709,12 @@ void DisassemblyContextMenu::showReverseJmpQuery() { QString type; - QJsonArray array = Core()->cmdj("pdj 1 @ " + RzAddressString(offset)).array(); - if (array.isEmpty()) { + CutterJson array = Core()->cmdj("pdj 1 @ " + RzAddressString(offset)); + if (!array.size()) { return; } - type = array.first().toObject()["type"].toString(); + type = array.first()["type"].toString(); if (type == "cjmp") { actionJmpReverse.setVisible(true); } else { diff --git a/src/widgets/BacktraceWidget.cpp b/src/widgets/BacktraceWidget.cpp index 793813d7..433a1b1e 100644 --- a/src/widgets/BacktraceWidget.cpp +++ b/src/widgets/BacktraceWidget.cpp @@ -44,13 +44,11 @@ void BacktraceWidget::updateContents() void BacktraceWidget::setBacktraceGrid() { - QJsonArray backtraceValues = Core()->getBacktrace().array(); int i = 0; - for (const QJsonValue &value : backtraceValues) { - QJsonObject backtraceItem = value.toObject(); - QString progCounter = RzAddressString(backtraceItem["pc"].toVariant().toULongLong()); - QString stackPointer = RzAddressString(backtraceItem["sp"].toVariant().toULongLong()); - int frameSize = backtraceItem["frame_size"].toVariant().toInt(); + for (CutterJson backtraceItem : Core()->getBacktrace()) { + QString progCounter = RzAddressString(backtraceItem["pc"].toRVA()); + QString stackPointer = RzAddressString(backtraceItem["sp"].toRVA()); + st64 frameSize = backtraceItem["frame_size"].toSt64(); QString funcName = backtraceItem["fname"].toString(); QString desc = backtraceItem["desc"].toString(); diff --git a/src/widgets/CallGraph.cpp b/src/widgets/CallGraph.cpp index 2bd16b73..c66a862e 100644 --- a/src/widgets/CallGraph.cpp +++ b/src/widgets/CallGraph.cpp @@ -77,8 +77,7 @@ void CallGraphView::loadCurrentGraph() blockContent.clear(); blocks.clear(); - QJsonDocument functionsDoc = Core()->cmdj(global ? "agCj" : QString("agcj @ %1").arg(address)); - auto nodes = functionsDoc.array(); + CutterJson nodes = Core()->cmdj(global ? "agCj" : QString("agcj @ %1").arg(address)); QHash idMapping; @@ -91,11 +90,10 @@ void CallGraphView::loadCurrentGraph() return itemId; }; - for (const QJsonValueRef &value : nodes) { - QJsonObject block = value.toObject(); - QString name = block["name"].toVariant().toString(); + for (CutterJson block : nodes) { + QString name = block["name"].toString(); - auto edges = block["imports"].toArray(); + auto edges = block["imports"]; GraphLayout::GraphBlock layoutBlock; layoutBlock.entry = getId(name); for (auto edge : edges) { diff --git a/src/widgets/ColorThemeListView.h b/src/widgets/ColorThemeListView.h index a1eb5103..8525312d 100644 --- a/src/widgets/ColorThemeListView.h +++ b/src/widgets/ColorThemeListView.h @@ -3,6 +3,7 @@ #include #include +#include #include #include #include diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index c641b8b0..4f49739a 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -32,16 +32,16 @@ Dashboard::~Dashboard() {} void Dashboard::updateContents() { - QJsonDocument docu = Core()->getFileInfo(); - QJsonObject item = docu.object()["core"].toObject(); - QJsonObject item2 = docu.object()["bin"].toObject(); + CutterJson docu = Core()->getFileInfo(); + CutterJson item = docu["core"]; + CutterJson item2 = docu["bin"]; setPlainText(this->ui->fileEdit, item["file"].toString()); setPlainText(this->ui->formatEdit, item["format"].toString()); setPlainText(this->ui->modeEdit, item["mode"].toString()); setPlainText(this->ui->typeEdit, item["type"].toString()); - setPlainText(this->ui->sizeEdit, qhelpers::formatBytecount(item["size"].toDouble())); - setPlainText(this->ui->fdEdit, QString::number(item["fd"].toDouble())); + setPlainText(this->ui->sizeEdit, qhelpers::formatBytecount(item["size"].toUt64())); + setPlainText(this->ui->fdEdit, QString::number(item["fd"].toUt64())); setPlainText(this->ui->archEdit, item2["arch"].toString()); setPlainText(this->ui->langEdit, item2["lang"].toString().toUpper()); @@ -52,7 +52,7 @@ void Dashboard::updateContents() setPlainText(this->ui->endianEdit, item2["endian"].toString()); setPlainText(this->ui->compilationDateEdit, item2["compiled"].toString()); setPlainText(this->ui->compilerEdit, item2["compiler"].toString()); - setPlainText(this->ui->bitsEdit, QString::number(item2["bits"].toDouble())); + setPlainText(this->ui->bitsEdit, QString::number(item2["bits"].toUt64())); if (!item2["relro"].toString().isEmpty()) { QString relro = item2["relro"].toString().section(QLatin1Char(' '), 0, 0); @@ -62,7 +62,7 @@ void Dashboard::updateContents() setPlainText(this->ui->relroEdit, "N/A"); } - setPlainText(this->ui->baddrEdit, RzAddressString(item2["baddr"].toVariant().toULongLong())); + setPlainText(this->ui->baddrEdit, RzAddressString(item2["baddr"].toRVA())); // set booleans setBool(this->ui->vaEdit, item2, "va"); @@ -110,16 +110,16 @@ void Dashboard::updateContents() hashesLayout->addRow(new QLabel(label), hashLineEdit); } - QJsonObject analinfo = Core()->cmdj("aaij").object(); - setPlainText(ui->functionsLineEdit, QString::number(analinfo["fcns"].toInt())); - setPlainText(ui->xRefsLineEdit, QString::number(analinfo["xrefs"].toInt())); - setPlainText(ui->callsLineEdit, QString::number(analinfo["calls"].toInt())); - setPlainText(ui->stringsLineEdit, QString::number(analinfo["strings"].toInt())); - setPlainText(ui->symbolsLineEdit, QString::number(analinfo["symbols"].toInt())); - setPlainText(ui->importsLineEdit, QString::number(analinfo["imports"].toInt())); - setPlainText(ui->coverageLineEdit, QString::number(analinfo["covrage"].toInt()) + " bytes"); - setPlainText(ui->codeSizeLineEdit, QString::number(analinfo["codesz"].toInt()) + " bytes"); - setPlainText(ui->percentageLineEdit, QString::number(analinfo["percent"].toInt()) + "%"); + CutterJson analinfo = Core()->cmdj("aaij"); + setPlainText(ui->functionsLineEdit, QString::number(analinfo["fcns"].toSt64())); + setPlainText(ui->xRefsLineEdit, QString::number(analinfo["xrefs"].toSt64())); + setPlainText(ui->callsLineEdit, QString::number(analinfo["calls"].toSt64())); + setPlainText(ui->stringsLineEdit, QString::number(analinfo["strings"].toSt64())); + setPlainText(ui->symbolsLineEdit, QString::number(analinfo["symbols"].toSt64())); + setPlainText(ui->importsLineEdit, QString::number(analinfo["imports"].toSt64())); + setPlainText(ui->coverageLineEdit, QString::number(analinfo["covrage"].toSt64()) + " bytes"); + setPlainText(ui->codeSizeLineEdit, QString::number(analinfo["codesz"].toSt64()) + " bytes"); + setPlainText(ui->percentageLineEdit, QString::number(analinfo["percent"].toSt64()) + "%"); QStringList libs = Core()->cmdList("il"); if (!libs.isEmpty()) { @@ -155,10 +155,10 @@ void Dashboard::updateContents() QStringList stats = Core()->getStats(); // Check if signature info and version info available - if (Core()->getSignatureInfo().isEmpty()) { + if (!Core()->getSignatureInfo().size()) { ui->certificateButton->setEnabled(false); } - if (Core()->getFileVersionInfo().isEmpty()) { + if (!Core()->getFileVersionInfo().size()) { ui->versioninfoButton->setEnabled(false); } } @@ -173,8 +173,7 @@ void Dashboard::on_certificateButton_clicked() viewDialog = new QDialog(this); view = new CutterTreeView(viewDialog); model = new JsonModel(); - QJsonDocument qjsonCertificatesDoc = Core()->getSignatureInfo(); - qstrCertificates = qjsonCertificatesDoc.toJson(QJsonDocument::Compact); + qstrCertificates = Core()->getSignatureInfo().toJson(); } if (!viewDialog->isVisible()) { std::string strCertificates = qstrCertificates.toUtf8().constData(); @@ -230,9 +229,9 @@ void Dashboard::setPlainText(QLineEdit *textBox, const QString &text) * @param textBox * @param isTrue */ -void Dashboard::setBool(QLineEdit *textBox, const QJsonObject &jsonObject, const QString &key) +void Dashboard::setBool(QLineEdit *textBox, const CutterJson &jsonObject, const char *key) { - if (jsonObject.contains(key)) { + if (jsonObject[key].valid()) { if (jsonObject[key].toBool()) { setPlainText(textBox, tr("True")); } else { diff --git a/src/widgets/Dashboard.h b/src/widgets/Dashboard.h index 45e578f6..61a2c677 100644 --- a/src/widgets/Dashboard.h +++ b/src/widgets/Dashboard.h @@ -3,6 +3,7 @@ #include #include +#include "core/Cutter.h" #include "CutterDockWidget.h" QT_BEGIN_NAMESPACE @@ -32,7 +33,7 @@ private slots: private: std::unique_ptr ui; void setPlainText(QLineEdit *textBox, const QString &text); - void setBool(QLineEdit *textBox, const QJsonObject &jsonObject, const QString &key); + void setBool(QLineEdit *textBox, const CutterJson &jsonObject, const char *key); QWidget *hashesWidget = nullptr; }; diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index e4bb05b8..09dacdd2 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -182,12 +182,11 @@ void DisassemblerGraphView::loadCurrentGraph() .set("asm.lines", false) .set("asm.lines.fcn", false); - QJsonArray functions; + CutterJson functions; RzAnalysisFunction *fcn = Core()->functionIn(seekable->getOffset()); if (fcn) { currentFcnAddr = fcn->addr; - QJsonDocument functionsDoc = Core()->cmdj("agJ " + RzAddressString(fcn->addr)); - functions = functionsDoc.array(); + functions = Core()->cmdj("agJ " + RzAddressString(fcn->addr)); } disassembly_blocks.clear(); @@ -198,7 +197,7 @@ void DisassemblerGraphView::loadCurrentGraph() highlight_token = nullptr; } - emptyGraph = functions.isEmpty(); + emptyGraph = !functions.size(); if (emptyGraph) { // If there's no function to print, just add a message if (!emptyText) { @@ -215,8 +214,7 @@ void DisassemblerGraphView::loadCurrentGraph() // Refresh global "empty graph" variable so other widget know there is nothing to show here Core()->setGraphEmpty(emptyGraph); - QJsonValue funcRef = functions.first(); - QJsonObject func = funcRef.toObject(); + CutterJson func = functions.first(); windowTitle = tr("Graph"); QString funcName = func["name"].toString().trimmed(); @@ -227,15 +225,14 @@ void DisassemblerGraphView::loadCurrentGraph() } emit nameChanged(windowTitle); - RVA entry = func["offset"].toVariant().toULongLong(); + RVA entry = func["offset"].toRVA(); setEntry(entry); - for (const QJsonValueRef &value : func["blocks"].toArray()) { - QJsonObject block = value.toObject(); - RVA block_entry = block["offset"].toVariant().toULongLong(); - RVA block_size = block["size"].toVariant().toULongLong(); - RVA block_fail = block["fail"].toVariant().toULongLong(); - RVA block_jump = block["jump"].toVariant().toULongLong(); + for (CutterJson block : func["blocks"]) { + RVA block_entry = block["offset"].toRVA(); + RVA block_size = block["size"].toRVA(); + RVA block_fail = block["fail"].toRVA(); + RVA block_jump = block["jump"].toRVA(); DisassemblyBlock db; GraphBlock gb; @@ -259,30 +256,29 @@ void DisassemblerGraphView::loadCurrentGraph() gb.edges.emplace_back(block_jump); } - QJsonObject switchOp = block["switchop"].toObject(); - if (!switchOp.isEmpty()) { - QJsonArray caseArray = switchOp["cases"].toArray(); - for (QJsonValue caseOpValue : caseArray) { - QJsonObject caseOp = caseOpValue.toObject(); - bool ok; - RVA caseJump = caseOp["jump"].toVariant().toULongLong(&ok); - if (!ok) { + CutterJson switchOp = block["switchop"]; + if (switchOp.size()) { + for (CutterJson caseOp : switchOp["cases"]) { + RVA caseJump = caseOp["jump"].toRVA(); + if (caseJump == RVA_INVALID) { continue; } gb.edges.emplace_back(caseJump); } } - QJsonArray opArray = block["ops"].toArray(); - for (int opIndex = 0; opIndex < opArray.size(); opIndex++) { - QJsonObject op = opArray[opIndex].toObject(); + CutterJson opArray = block["ops"]; + CutterJson::iterator iterator = opArray.begin(); + while (iterator != opArray.end()) { + CutterJson op = *iterator; Instr i; - i.addr = op["offset"].toVariant().toULongLong(); + i.addr = op["offset"].toUt64(); - if (opIndex < opArray.size() - 1) { + ++iterator; + + if (iterator != opArray.end()) { // get instruction size from distance to next instruction ... - RVA nextOffset = - opArray[opIndex + 1].toObject()["offset"].toVariant().toULongLong(); + RVA nextOffset = (*iterator)["offset"].toRVA(); i.size = nextOffset - i.addr; } else { // or to the end of the block. @@ -314,7 +310,7 @@ void DisassemblerGraphView::loadCurrentGraph() } cleanupEdges(blocks); - if (!func["blocks"].toArray().isEmpty()) { + if (func["blocks"].size()) { computeGraphPlacement(); } } diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index f77bae3d..ab92ecd9 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -562,7 +562,7 @@ void FunctionsWidget::refreshTree() importAddresses.insert(import.plt); } - mainAdress = (ut64)Core()->cmdj("iMj").object()["vaddr"].toInt(); + mainAdress = (ut64)Core()->cmdj("iMj")["vaddr"].toUt64(); functionModel->updateCurrentIndex(); functionModel->endResetModel(); diff --git a/src/widgets/ProcessesWidget.cpp b/src/widgets/ProcessesWidget.cpp index 28a1e335..b8e12435 100644 --- a/src/widgets/ProcessesWidget.cpp +++ b/src/widgets/ProcessesWidget.cpp @@ -106,14 +106,12 @@ QString ProcessesWidget::translateStatus(QString status) void ProcessesWidget::setProcessesGrid() { - QJsonArray processesValues = Core()->getChildProcesses(DEBUGGED_PID).array(); int i = 0; QFont font; - for (const QJsonValue &value : processesValues) { - QJsonObject processesItem = value.toObject(); - int pid = processesItem["pid"].toVariant().toInt(); - int uid = processesItem["uid"].toVariant().toInt(); + for (CutterJson processesItem : Core()->getChildProcesses(DEBUGGED_PID)) { + st64 pid = processesItem["pid"].toSt64(); + st64 uid = processesItem["uid"].toSt64(); QString status = translateStatus(processesItem["status"].toString()); QString path = processesItem["path"].toString(); bool current = processesItem["current"].toBool(); @@ -162,10 +160,9 @@ void ProcessesWidget::onActivated(const QModelIndex &index) // Verify that the selected pid is still in the processes list since dp= will // attach to any given id. If it isn't found simply update the UI. - QJsonArray processesValues = Core()->getChildProcesses(DEBUGGED_PID).array(); - for (QJsonValue value : processesValues) { - QString status = value.toObject()["status"].toString(); - if (pid == value.toObject()["pid"].toInt()) { + for (CutterJson value : Core()->getChildProcesses(DEBUGGED_PID)) { + QString status = value["status"].toString(); + if (pid == value["pid"].toSt64()) { if (QString(QChar(RZ_DBG_PROC_ZOMBIE)) == status || QString(QChar(RZ_DBG_PROC_DEAD)) == status) { QMessageBox msgBox; diff --git a/src/widgets/RegisterRefsWidget.cpp b/src/widgets/RegisterRefsWidget.cpp index adfd67af..d0cfb4dd 100644 --- a/src/widgets/RegisterRefsWidget.cpp +++ b/src/widgets/RegisterRefsWidget.cpp @@ -184,14 +184,13 @@ void RegisterRefsWidget::refreshRegisterRef() registerRefModel->beginResetModel(); - QList regRefs = Core()->getRegisterRefs(); registerRefs.clear(); - for (const QJsonObject ® : regRefs) { + for (const RegisterRef ® : Core()->getRegisterRefs()) { RegisterRefDescription desc; - desc.value = RzAddressString(reg["value"].toVariant().toULongLong()); - desc.reg = reg["name"].toVariant().toString(); - desc.refDesc = Core()->formatRefDesc(reg["ref"].toObject()); + desc.value = RzAddressString(reg.value); + desc.reg = reg.name; + desc.refDesc = Core()->formatRefDesc(reg.ref); registerRefs.push_back(desc); } diff --git a/src/widgets/RizinGraphWidget.cpp b/src/widgets/RizinGraphWidget.cpp index a0b88e15..346cf012 100644 --- a/src/widgets/RizinGraphWidget.cpp +++ b/src/widgets/RizinGraphWidget.cpp @@ -96,12 +96,11 @@ void GenericRizinGraphView::loadCurrentGraph() return; } - QJsonDocument functionsDoc = Core()->cmdj(QString("%1j").arg(graphCommand)); - auto nodes = functionsDoc.object()["nodes"].toArray(); + CutterJson functionsDoc = Core()->cmdj(QString("%1j").arg(graphCommand)); + auto nodes = functionsDoc["nodes"]; - for (const QJsonValueRef &value : nodes) { - QJsonObject block = value.toObject(); - uint64_t id = block["id"].toVariant().toULongLong(); + for (CutterJson block : nodes) { + uint64_t id = block["id"].toUt64(); QString content; QString title = block["title"].toString(); @@ -112,11 +111,11 @@ void GenericRizinGraphView::loadCurrentGraph() content = title + body; } - auto edges = block["out_nodes"].toArray(); + auto edges = block["out_nodes"]; GraphLayout::GraphBlock layoutBlock; layoutBlock.entry = id; for (auto edge : edges) { - auto targetId = edge.toVariant().toULongLong(); + auto targetId = edge.toUt64(); layoutBlock.edges.emplace_back(targetId); } diff --git a/src/widgets/StackWidget.cpp b/src/widgets/StackWidget.cpp index fd68db29..d673f8b1 100644 --- a/src/widgets/StackWidget.cpp +++ b/src/widgets/StackWidget.cpp @@ -145,16 +145,16 @@ StackModel::StackModel(QObject *parent) : QAbstractTableModel(parent) {} void StackModel::reload() { - QList stackItems = Core()->getStack(); + QList stackItems = Core()->getStack(); beginResetModel(); values.clear(); - for (const QJsonObject &stackItem : stackItems) { + for (const AddrRefs &stackItem : stackItems) { Item item; - item.offset = stackItem["addr"].toVariant().toULongLong(); - item.value = RzAddressString(stackItem["value"].toVariant().toULongLong()); - item.refDesc = Core()->formatRefDesc(stackItem["ref"].toObject()); + item.offset = stackItem.addr; + item.value = RzAddressString(stackItem.value); + item.refDesc = Core()->formatRefDesc(*stackItem.ref); values.push_back(item); } diff --git a/src/widgets/ThreadsWidget.cpp b/src/widgets/ThreadsWidget.cpp index b650e7a6..6cdde089 100644 --- a/src/widgets/ThreadsWidget.cpp +++ b/src/widgets/ThreadsWidget.cpp @@ -104,13 +104,11 @@ QString ThreadsWidget::translateStatus(QString status) void ThreadsWidget::setThreadsGrid() { - QJsonArray threadsValues = Core()->getProcessThreads(DEBUGGED_PID).array(); int i = 0; QFont font; - for (const QJsonValue &value : threadsValues) { - QJsonObject threadsItem = value.toObject(); - int pid = threadsItem["pid"].toVariant().toInt(); + for (CutterJson threadsItem : Core()->getProcessThreads(DEBUGGED_PID)) { + st64 pid = threadsItem["pid"].toSt64(); QString status = translateStatus(threadsItem["status"].toString()); QString path = threadsItem["path"].toString(); bool current = threadsItem["current"].toBool(); @@ -152,9 +150,8 @@ void ThreadsWidget::onActivated(const QModelIndex &index) // Verify that the selected tid is still in the threads list since dpt= will // attach to any given id. If it isn't found simply update the UI. - QJsonArray threadsValues = Core()->getProcessThreads(DEBUGGED_PID).array(); - for (QJsonValue value : threadsValues) { - if (tid == value.toObject()["pid"].toInt()) { + for (CutterJson value : Core()->getProcessThreads(DEBUGGED_PID)) { + if (tid == value["pid"].toSt64()) { Core()->setCurrentDebugThread(tid); break; } From b8243a2b615aaaf14cc7745fff69694337cc784d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 14 Mar 2022 10:09:35 +0100 Subject: [PATCH 081/240] Remove unused stats query (#2903) The views showing this info have been removed in the past, so it was unused. This also fixes some errors with latest rizin where zero-argument f does not exist anymore (it's now fl). --- src/core/Cutter.cpp | 26 -------------------------- src/core/Cutter.h | 1 - src/widgets/Dashboard.cpp | 3 --- 3 files changed, 30 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index bb0b661a..d5db389b 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -2653,32 +2653,6 @@ QList CutterCore::getMemoryMap() return ret; } -QStringList CutterCore::getStats() -{ - QStringList stats; - cmdRaw("fs functions"); - - // The cmd coomand is frequently used in this function because - // cmdRaw would not work with grep - stats << cmd("f~?").trimmed(); - - QString imps = cmd("ii~?").trimmed(); - stats << imps; - - cmdRaw("fs symbols"); - stats << cmd("f~?").trimmed(); - cmdRaw("fs strings"); - stats << cmd("f~?").trimmed(); - cmdRaw("fs relocs"); - stats << cmd("f~?").trimmed(); - cmdRaw("fs sections"); - stats << cmd("f~?").trimmed(); - cmdRaw("fs *"); - stats << cmd("f~?").trimmed(); - - return stats; -} - void CutterCore::setGraphEmpty(bool empty) { emptyGraph = empty; diff --git a/src/core/Cutter.h b/src/core/Cutter.h index c1e21e50..249da7ce 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -559,7 +559,6 @@ public: CutterJson getFileInfo(); CutterJson getSignatureInfo(); CutterJson getFileVersionInfo(); - QStringList getStats(); void setGraphEmpty(bool empty); bool isGraphEmpty(); diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index 4f49739a..c0d0cf87 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -151,9 +151,6 @@ void Dashboard::updateContents() QSpacerItem *spacer = new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding); ui->verticalLayout_2->addSpacerItem(spacer); - // Get stats for the graphs - QStringList stats = Core()->getStats(); - // Check if signature info and version info available if (!Core()->getSignatureInfo().size()) { ui->certificateButton->setEnabled(false); From 9441c3b470d3a85dc1bcad83079071ee7211b89d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 14 Mar 2022 09:49:52 +0100 Subject: [PATCH 082/240] Replace usage of wcj by C API --- src/common/IOModesController.cpp | 10 +++------- src/core/CutterCommon.h | 26 ++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/src/common/IOModesController.cpp b/src/common/IOModesController.cpp index 4fa29502..88378c10 100644 --- a/src/common/IOModesController.cpp +++ b/src/common/IOModesController.cpp @@ -77,16 +77,12 @@ bool IOModesController::prepareForWriting() bool IOModesController::allChangesComitted() { - // Get a list of available write changes - CutterJson changes = Core()->cmdj("wcj"); - - // Check if there is a change which isn't written to the file - for (CutterJson changeObject : changes) { - if (!changeObject["written"].toBool()) { + RzCoreLocked core(Core()); + for (auto c : CutterPVector(&core->io->cache)) { + if (!c->written) { return false; } } - return true; } diff --git a/src/core/CutterCommon.h b/src/core/CutterCommon.h index 3cbc1941..6d6f7e7a 100644 --- a/src/core/CutterCommon.h +++ b/src/core/CutterCommon.h @@ -25,6 +25,32 @@ (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); } +}; + // Global information for Cutter #define APPNAME "Cutter" From bca7a7a2a69635b59a22147ec62325043a4dcdc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 14 Mar 2022 10:01:48 +0100 Subject: [PATCH 083/240] Rewrite isWriteModeEnabled() with API This also introduces a slight behavioral change: Previously, only the core file with the "raised" io desc was checked, which is RzIO.desc. But that member is deprecated for good reasons, so now we just check if there is any core file whose primary fd has write enabled. --- src/core/Cutter.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index d5db389b..b0731590 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -4042,12 +4042,18 @@ void CutterCore::setWriteMode(bool enabled) bool CutterCore::isWriteModeEnabled() { - for (CutterJson v : cmdj("oj")) { - if (v["raised"].toBool()) { - return v["writable"].toBool(); + CORE_LOCK(); + RzListIter *it; + RzCoreFile *cf; + CutterRzListForeach (core->files, it, RzCoreFile, cf) { + RzIODesc *desc = rz_io_desc_get(core->io, cf->fd); + if (!desc) { + continue; + } + if (desc->perm & RZ_PERM_W) { + return true; } } - return false; } From 72ab12a23d9f75e6a453484565f73323e5bc365f Mon Sep 17 00:00:00 2001 From: yossizap Date: Tue, 15 Mar 2022 10:58:09 +0000 Subject: [PATCH 084/240] Update rizin submodule (#2900) This is also a partial fix for #2897 --- rizin | 2 +- src/core/Cutter.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rizin b/rizin index d43cbf5c..dd81b662 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit d43cbf5ce74fd7333032144a8e0fc2f74ce9803a +Subproject commit dd81b6629a45ec3d221042ed9729b50cd3c478c5 diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index b0731590..43edba36 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -737,7 +737,7 @@ QString CutterCore::getInstructionOpcode(RVA addr) void CutterCore::editInstruction(RVA addr, const QString &inst) { CORE_LOCK(); - rz_core_write_assembly(core, addr, inst.trimmed().toStdString().c_str(), false, false); + rz_core_write_assembly(core, addr, inst.trimmed().toStdString().c_str()); emit instructionChanged(addr); } From 15282d9bc5ecaf5519c5e6418004932e75ca7cfd Mon Sep 17 00:00:00 2001 From: alexthesys Date: Thu, 2 Dec 2021 12:35:10 +0300 Subject: [PATCH 085/240] Hexeditor: add option to write hex bytes --- src/widgets/HexWidget.cpp | 41 ++++++++++++++++++++++++++++++++++++++- src/widgets/HexWidget.h | 1 + 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index 784528a9..a3e0ae46 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -147,7 +147,11 @@ HexWidget::HexWidget(QWidget *parent) connect(actionWrite64, &QAction::triggered, this, &HexWidget::w_write64); actionsWriteString.append(actionWrite64); - actionsWriteOther.reserve(4); + actionsWriteOther.reserve(5); + QAction *actionWriteBytes = new QAction(tr("Write hex bytes"), this); + connect(actionWriteBytes, &QAction::triggered, this, &HexWidget::w_writeBytes); + actionsWriteOther.append(actionWriteBytes); + QAction *actionWriteZeros = new QAction(tr("Write zeros"), this); connect(actionWriteZeros, &QAction::triggered, this, &HexWidget::w_writeZeros); actionsWriteOther.append(actionWriteZeros); @@ -730,6 +734,41 @@ void HexWidget::w_increaseDecrease() refresh(); } +void HexWidget::w_writeBytes() +{ + if (!ioModesController.prepareForWriting()) { + return; + } + bool ok = false; + + int size = INT_MAX; + if (!selection.isEmpty() && selection.size() <= INT_MAX) { + size = static_cast(selection.size()); + } + + QInputDialog d; + d.setInputMode(QInputDialog::InputMode::TextInput); + QByteArray bytes = d.getText(this, tr("Write hex bytes"), tr("Hex byte string:"), + QLineEdit::Normal, "", &ok) + .toUtf8(); + const int offset = bytes.startsWith("\\x") ? 2 : 0; + const int incr = offset + 2; + const int bytes_size = qMin(bytes.size() / incr, size); + if (ok && bytes_size) { + uint8_t *buf = (uint8_t *)malloc(static_cast(bytes_size)); + if (!buf) { + return; + } + for (int i = 0, j = 0, sz = bytes.size(); i < sz; i += incr, j++) { + buf[j] = static_cast(bytes.mid(i + offset, 2).toInt(nullptr, 16)); + } + RzCoreLocked core(Core()); + rz_core_write_at(core, getLocationAddress(), buf, bytes_size); + free(buf); + refresh(); + } +} + void HexWidget::w_writeZeros() { if (!ioModesController.prepareForWriting()) { diff --git a/src/widgets/HexWidget.h b/src/widgets/HexWidget.h index 1489ef85..5a6a15f0 100644 --- a/src/widgets/HexWidget.h +++ b/src/widgets/HexWidget.h @@ -315,6 +315,7 @@ private slots: // Write command slots void w_writeString(); void w_increaseDecrease(); + void w_writeBytes(); void w_writeZeros(); void w_write64(); void w_writeRandom(); From c535badacdfab236c719556cac5b603cb83a14d6 Mon Sep 17 00:00:00 2001 From: alexthesys Date: Tue, 7 Dec 2021 11:57:05 +0300 Subject: [PATCH 086/240] Convert if-block to early return --- src/widgets/HexWidget.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index a3e0ae46..334176be 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -754,19 +754,20 @@ void HexWidget::w_writeBytes() const int offset = bytes.startsWith("\\x") ? 2 : 0; const int incr = offset + 2; const int bytes_size = qMin(bytes.size() / incr, size); - if (ok && bytes_size) { - uint8_t *buf = (uint8_t *)malloc(static_cast(bytes_size)); - if (!buf) { - return; - } - for (int i = 0, j = 0, sz = bytes.size(); i < sz; i += incr, j++) { - buf[j] = static_cast(bytes.mid(i + offset, 2).toInt(nullptr, 16)); - } - RzCoreLocked core(Core()); - rz_core_write_at(core, getLocationAddress(), buf, bytes_size); - free(buf); - refresh(); + if (!ok || !bytes_size) { + return; } + uint8_t *buf = (uint8_t *)malloc(static_cast(bytes_size)); + if (!buf) { + return; + } + for (int i = 0, j = 0, sz = bytes.size(); i < sz; i += incr, j++) { + buf[j] = static_cast(bytes.mid(i + offset, 2).toInt(nullptr, 16)); + } + RzCoreLocked core(Core()); + rz_core_write_at(core, getLocationAddress(), buf, bytes_size); + free(buf); + refresh(); } void HexWidget::w_writeZeros() From b9df65a6c9c73a1a1faf8ec5c122802d54f2c622 Mon Sep 17 00:00:00 2001 From: SR_team Date: Mon, 28 Mar 2022 15:12:09 +0300 Subject: [PATCH 087/240] Update includes compat with KF5.92 on some distributions (#2912) With KF5.92 headers KSyntaxHighlighting/{header}.h copied to KSyntaxHighlighting/ksyntaxhighlighting/{header}.h. Headers KSyntaxHighlighting/{Header} now include ksyntaxhighlighting/{header}.h instead of {header}.h. Than on some distros like ArchLinux headers KSyntaxHighlighting/{header}.h removed, because it copies of KSyntaxHighlighting/ksyntaxhighlighting/{header}.h and because KSyntaxHighlighting/{Header} now include ksyntaxhighlighting/{header}.h. --- src/common/Configuration.cpp | 6 +++--- src/common/SyntaxHighlighter.cpp | 2 +- src/common/SyntaxHighlighter.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index cc8690b4..0a73eb34 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -7,9 +7,9 @@ #include #ifdef CUTTER_ENABLE_KSYNTAXHIGHLIGHTING -# include -# include -# include +# include +# include +# include #endif #include "common/ColorThemeWorker.h" diff --git a/src/common/SyntaxHighlighter.cpp b/src/common/SyntaxHighlighter.cpp index 64a2038e..b15afc63 100644 --- a/src/common/SyntaxHighlighter.cpp +++ b/src/common/SyntaxHighlighter.cpp @@ -5,7 +5,7 @@ # include "Configuration.h" -# include +# include SyntaxHighlighter::SyntaxHighlighter(QTextDocument *document) : KSyntaxHighlighting::SyntaxHighlighter(document) diff --git a/src/common/SyntaxHighlighter.h b/src/common/SyntaxHighlighter.h index b9e88970..7846c227 100644 --- a/src/common/SyntaxHighlighter.h +++ b/src/common/SyntaxHighlighter.h @@ -10,7 +10,7 @@ #ifdef CUTTER_ENABLE_KSYNTAXHIGHLIGHTING -# include +# include class SyntaxHighlighter : public KSyntaxHighlighting::SyntaxHighlighter { From fc3f072ed762079d2248b513ddb3d3a2a9600a84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 28 Mar 2022 19:21:25 +0200 Subject: [PATCH 088/240] Add missing overrides to SectionsModel --- src/widgets/SectionsWidget.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/widgets/SectionsWidget.h b/src/widgets/SectionsWidget.h index 9a7e9638..8fcdafcf 100644 --- a/src/widgets/SectionsWidget.h +++ b/src/widgets/SectionsWidget.h @@ -51,11 +51,11 @@ public: SectionsModel(QList *sections, QObject *parent = nullptr); - int rowCount(const QModelIndex &parent = QModelIndex()) const; - int columnCount(const QModelIndex &parent = QModelIndex()) const; + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; - QVariant data(const QModelIndex &index, int role) const; - QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + QVariant data(const QModelIndex &index, int role) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; RVA address(const QModelIndex &index) const override; QString name(const QModelIndex &index) const override; From 206fee601b27f7809765c531c9e754bad7a19a69 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 28 Mar 2022 19:32:33 +0200 Subject: [PATCH 089/240] Fix a strange comparison --- src/widgets/HexWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index 334176be..39d9d2e2 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -726,7 +726,7 @@ void HexWidget::w_increaseDecrease() } int64_t value = (int64_t)d.getValue(); uint8_t sz = d.getNBytes(); - if (!d.getMode() == IncrementDecrementDialog::Increase) { + if (d.getMode() == IncrementDecrementDialog::Decrease) { value *= -1; } RzCoreLocked core(Core()); From 72a3815c0137ed49b8e9cacb183ed56946c79e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 28 Mar 2022 20:19:58 +0200 Subject: [PATCH 090/240] Remove unnessecary str in setToData() (Fix #2901) --- src/core/Cutter.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 43edba36..85924471 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -834,11 +834,9 @@ void CutterCore::setToData(RVA addr, int size, int repeat) } CORE_LOCK(); - rz_meta_del(core->analysis, RZ_META_TYPE_DATA, addr, 1); RVA address = addr; - auto name = QString(size).toStdString(); for (int i = 0; i < repeat; ++i, address += size) { - rz_meta_set(core->analysis, RZ_META_TYPE_DATA, address, size, name.c_str()); + rz_meta_set(core->analysis, RZ_META_TYPE_DATA, address, size, nullptr); } emit instructionChanged(addr); } From 2c31d38d859d1b91a860932a3f313570bb1a22e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 28 Mar 2022 20:43:47 +0200 Subject: [PATCH 091/240] Rewrite getVariables with API This also avoids annoying "ERROR: No function found in ..." beging printed by afvj when right-clicking anywhere outside a function. The heuristics in functionIn() also have been adjusted to prefer the function that has its entrypoint at the given addr, if there is any. --- src/core/Cutter.cpp | 54 ++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 18 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 85924471..5c9ba1d0 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1221,10 +1221,13 @@ QString CutterCore::disassembleSingleInstruction(RVA addr) RzAnalysisFunction *CutterCore::functionIn(ut64 addr) { CORE_LOCK(); + RzAnalysisFunction *fcn = rz_analysis_get_function_at(core->analysis, addr); + if (fcn) { + return fcn; + } RzList *fcns = rz_analysis_get_functions_in(core->analysis, addr); - RzAnalysisFunction *fcn = !rz_list_empty(fcns) - ? reinterpret_cast(rz_list_first(fcns)) - : nullptr; + fcn = !rz_list_empty(fcns) ? reinterpret_cast(rz_list_first(fcns)) + : nullptr; rz_list_free(fcns); return fcn; } @@ -1750,22 +1753,37 @@ CutterJson CutterCore::getRegisterValues() QList CutterCore::getVariables(RVA at) { QList ret; - CutterJson varsObject = cmdj(QString("afvj @ %1").arg(at)); - - auto addVars = [&](VariableDescription::RefType refType, const CutterJson &array) { - for (CutterJson varObject : array) { - VariableDescription desc; - desc.refType = refType; - desc.name = varObject["name"].toString(); - desc.type = varObject["type"].toString(); - ret << desc; + CORE_LOCK(); + RzAnalysisFunction *fcn = functionIn(at); + if (!fcn) { + return ret; + } + for (auto var : CutterPVector(&fcn->vars)) { + VariableDescription desc; + switch (var->kind) { + case RZ_ANALYSIS_VAR_KIND_BPV: + desc.refType = VariableDescription::RefType::BP; + break; + case RZ_ANALYSIS_VAR_KIND_SPV: + desc.refType = VariableDescription::RefType::SP; + break; + case RZ_ANALYSIS_VAR_KIND_REG: + default: + desc.refType = VariableDescription::RefType::Reg; + break; } - }; - - addVars(VariableDescription::RefType::SP, varsObject["sp"]); - addVars(VariableDescription::RefType::BP, varsObject["bp"]); - addVars(VariableDescription::RefType::Reg, varsObject["reg"]); - + if (!var->name || !var->type) { + continue; + } + desc.name = QString::fromUtf8(var->name); + char *tn = rz_type_as_string(core->analysis->typedb, var->type); + if (!tn) { + continue; + } + desc.type = QString::fromUtf8(tn); + rz_mem_free(tn); + ret.push_back(desc); + } return ret; } From b92ad1914845d1d83f5782afddfe57bb1b5261bd Mon Sep 17 00:00:00 2001 From: Nirmal Manoj Date: Mon, 4 Oct 2021 18:07:49 +0530 Subject: [PATCH 092/240] Use RzAnnotatedCode from JSDec (pddA) --- src/common/Decompiler.cpp | 102 ++++++++++++++++++++++++++------------ src/core/CutterJson.h | 1 + 2 files changed, 72 insertions(+), 31 deletions(-) diff --git a/src/common/Decompiler.cpp b/src/common/Decompiler.cpp index 94892075..7653f1d2 100644 --- a/src/common/Decompiler.cpp +++ b/src/common/Decompiler.cpp @@ -10,6 +10,75 @@ Decompiler::Decompiler(const QString &id, const QString &name, QObject *parent) { } +static char *jsonToStrdup(const CutterJson &str) +{ + const RzJson *j = str.lowLevelValue(); + if (!j || j->type != RZ_JSON_STRING) { + return NULL; + } + return rz_str_new(j->str_value); +} + +static RzAnnotatedCode *parseJsonCode(CutterJson &json) +{ + char *raw_code = jsonToStrdup(json["code"]); + if (!raw_code) { + return NULL; + } + RzAnnotatedCode *code = rz_annotated_code_new(raw_code); + if (!code) { + return NULL; + } + for (const auto &jsonAnnotation : json["annotations"]) { + RzCodeAnnotation annotation = {}; + annotation.start = jsonAnnotation["start"].toUt64(); + annotation.end = jsonAnnotation["end"].toUt64(); + QString type = jsonAnnotation["type"].toString(); + if (type == "offset") { + annotation.type = RZ_CODE_ANNOTATION_TYPE_OFFSET; + annotation.offset.offset = jsonAnnotation["offset"].toString().toULongLong(); + } else if (type == "function_name") { + annotation.type = RZ_CODE_ANNOTATION_TYPE_FUNCTION_NAME; + annotation.reference.name = jsonToStrdup(jsonAnnotation["name"]); + annotation.reference.offset = jsonAnnotation["offset"].toString().toULongLong(); + } else if (type == "global_variable") { + annotation.type = RZ_CODE_ANNOTATION_TYPE_GLOBAL_VARIABLE; + annotation.reference.offset = jsonAnnotation["offset"].toString().toULongLong(); + } else if (type == "constant_variable") { + annotation.type = RZ_CODE_ANNOTATION_TYPE_CONSTANT_VARIABLE; + annotation.reference.offset = jsonAnnotation["offset"].toString().toULongLong(); + } else if (type == "local_variable") { + annotation.type = RZ_CODE_ANNOTATION_TYPE_LOCAL_VARIABLE; + annotation.variable.name = jsonToStrdup(jsonAnnotation["name"]); + } else if (type == "function_parameter") { + annotation.type = RZ_CODE_ANNOTATION_TYPE_FUNCTION_PARAMETER; + annotation.variable.name = jsonToStrdup(jsonAnnotation["name"]); + } else if (type == "syntax_highlight") { + annotation.type = RZ_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT; + QString highlightType = jsonAnnotation["syntax_highlight"].toString(); + if (highlightType == "keyword") { + annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_KEYWORD; + } else if (highlightType == "comment") { + annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_COMMENT; + } else if (highlightType == "datatype") { + annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_DATATYPE; + } else if (highlightType == "function_name") { + annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_NAME; + } else if (highlightType == "function_parameter") { + annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_PARAMETER; + } else if (highlightType == "local_variable") { + annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_LOCAL_VARIABLE; + } else if (highlightType == "constant_variable") { + annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_CONSTANT_VARIABLE; + } else if (highlightType == "global_variable") { + annotation.syntax_highlight.type = RZ_SYNTAX_HIGHLIGHT_TYPE_GLOBAL_VARIABLE; + } + } + rz_annotated_code_add_annotation(code, &annotation); + } + return code; +} + RzAnnotatedCode *Decompiler::makeWarning(QString warningMessage) { std::string temporary = warningMessage.toStdString(); @@ -31,7 +100,7 @@ void JSDecDecompiler::decompileAt(RVA addr) if (task) { return; } - task = new RizinCmdTask("pddj @ " + QString::number(addr)); + task = new RizinCmdTask("pddA @ " + QString::number(addr)); connect(task, &RizinCmdTask::finished, this, [this]() { CutterJson json = task->getResultJson(); delete task; @@ -40,36 +109,7 @@ void JSDecDecompiler::decompileAt(RVA addr) emit finished(Decompiler::makeWarning(tr("Failed to parse JSON from jsdec"))); return; } - RzAnnotatedCode *code = rz_annotated_code_new(nullptr); - QString codeString = ""; - for (auto line : json["log"]) { - if (line.type() != RZ_JSON_STRING) { - continue; - } - codeString.append(line.toString() + "\n"); - } - - for (auto lineObject : json["lines"]) { - if (!lineObject.size()) { - continue; - } - RzCodeAnnotation annotationi = {}; - annotationi.start = codeString.length(); - codeString.append(lineObject["str"].toString() + "\n"); - annotationi.end = codeString.length(); - annotationi.type = RZ_CODE_ANNOTATION_TYPE_OFFSET; - annotationi.offset.offset = lineObject["offset"].toUt64(); - rz_annotated_code_add_annotation(code, &annotationi); - } - - for (auto line : json["errors"]) { - if (line.type() != RZ_JSON_STRING) { - continue; - } - codeString.append(line.toString() + "\n"); - } - std::string tmp = codeString.toStdString(); - code->code = strdup(tmp.c_str()); + RzAnnotatedCode *code = parseJsonCode(json); emit finished(code); }); task->startTask(); diff --git a/src/core/CutterJson.h b/src/core/CutterJson.h index 042ca84b..e8dd9819 100644 --- a/src/core/CutterJson.h +++ b/src/core/CutterJson.h @@ -89,6 +89,7 @@ public: size_t size() const { return has_children() ? value->children.count : 0; } RzJsonType type() const { return value ? value->type : RZ_JSON_NULL; } bool valid() const { return value ? true : false; } + const RzJson *lowLevelValue() const { return value; } private: bool has_children() const From 1ed19e7fc4d5e8c659f0ca45f624c579b7f50c01 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Wed, 30 Mar 2022 10:41:37 +0200 Subject: [PATCH 093/240] Fixed formatting (#2917) --- src/dialogs/preferences/AsmOptionsWidget.cpp | 2 +- src/dialogs/preferences/GraphOptionsWidget.cpp | 2 +- src/menus/FlirtContextMenu.h | 3 +-- src/widgets/DecompilerWidget.cpp | 1 - src/widgets/HeapDockWidget.h | 2 +- 5 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/dialogs/preferences/AsmOptionsWidget.cpp b/src/dialogs/preferences/AsmOptionsWidget.cpp index 7004b4b4..08abec50 100644 --- a/src/dialogs/preferences/AsmOptionsWidget.cpp +++ b/src/dialogs/preferences/AsmOptionsWidget.cpp @@ -242,7 +242,7 @@ void AsmOptionsWidget::on_varsubCheckBox_toggled(bool checked) triggerAsmOptionsChanged(); } -void AsmOptionsWidget::on_previewCheckBox_toggled( bool checked ) +void AsmOptionsWidget::on_previewCheckBox_toggled(bool checked) { Config()->setPreviewValue(checked); triggerAsmOptionsChanged(); diff --git a/src/dialogs/preferences/GraphOptionsWidget.cpp b/src/dialogs/preferences/GraphOptionsWidget.cpp index 7a896174..13bb0922 100644 --- a/src/dialogs/preferences/GraphOptionsWidget.cpp +++ b/src/dialogs/preferences/GraphOptionsWidget.cpp @@ -85,7 +85,7 @@ void GraphOptionsWidget::on_graphOffsetCheckBox_toggled(bool checked) triggerOptionsChanged(); } -void GraphOptionsWidget::on_graphPreviewCheckBox_toggled( bool checked ) +void GraphOptionsWidget::on_graphPreviewCheckBox_toggled(bool checked) { Config()->setGraphPreview(checked); triggerOptionsChanged(); diff --git a/src/menus/FlirtContextMenu.h b/src/menus/FlirtContextMenu.h index 6cf12cae..ec57c7e0 100644 --- a/src/menus/FlirtContextMenu.h +++ b/src/menus/FlirtContextMenu.h @@ -33,8 +33,7 @@ protected: void setHasTarget(bool hasTarget); QAction *actionApplySignature; QAction *actionCopyLine; - QAction *actionShowContents; FlirtDescription entry; }; -#endif // FlirtCONTEXTMENU_H +#endif // FLIRT_CONTEXTMENU_H diff --git a/src/widgets/DecompilerWidget.cpp b/src/widgets/DecompilerWidget.cpp index a6dd58af..9414f118 100644 --- a/src/widgets/DecompilerWidget.cpp +++ b/src/widgets/DecompilerWidget.cpp @@ -551,7 +551,6 @@ void DecompilerWidget::highlightBreakpoints() for (RVA &bp : functionBreakpoints) { if (bp == RVA_INVALID) { continue; - ; } cursor = getCursorForAddress(bp); if (!cursor.isNull()) { diff --git a/src/widgets/HeapDockWidget.h b/src/widgets/HeapDockWidget.h index 4e507c39..a8a324cb 100644 --- a/src/widgets/HeapDockWidget.h +++ b/src/widgets/HeapDockWidget.h @@ -22,7 +22,7 @@ private: enum Allocator { Glibc = 0, AllocatorCount }; Ui::HeapDockWidget *ui; MainWindow *main; - QWidget* currentHeapWidget = nullptr; + QWidget *currentHeapWidget = nullptr; }; #endif // HEAPDOCKWIDGET_H From 5e8aa4f9937d37357f205a40a2d3166f76376d42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Wed, 30 Mar 2022 10:57:10 +0200 Subject: [PATCH 094/240] Update windows CI to 2019 --- .github/workflows/ccpp.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 39b07cbe..64a3f7f6 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -19,13 +19,13 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, ubuntu-18.04, macos-latest, windows-2016] + os: [ubuntu-20.04, ubuntu-18.04, macos-latest, windows-2019] python-version: [3.7.x] system-deps: [false] cc-override: [default] cxx-override: [default] include: - - os: windows-2016 + - os: windows-2019 package: true - os: ubuntu-18.04 # ensure that Cutter can be built at least in basic config on Ubuntu 18.04 using sytem libraries python-version: 3.6.x @@ -213,7 +213,7 @@ jobs: set ARCH=x64 set CUTTER_DEPS=%CD%\cutter-deps set PATH=%CD%\cutter-deps\qt\bin;%PATH% - call "C:\Program Files (x86)\Microsoft Visual Studio\2017\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 + call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 call scripts\prepare_breakpad.bat cd mkdir build From 62d75c9391b89fb5ff67ae9438f876a6c79df700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Thu, 31 Mar 2022 12:49:37 +0200 Subject: [PATCH 095/240] Extend cmake config files with deps, version, etc. (#2916) This improves how the installed CutterConfig.cmake can be used for native plugin development: * Transitive dependencies are resolved automatically * Version file is included * Cutter_USER_PLUGINDIR is set to a path that plugins can use as a default install destination src/plugins/sample-cpp/CMakeLists.txt is an example for how to use it. Rizin was also updated to prevent an error with multiple `find_package()` calls. --- CMakeLists.txt | 8 +++--- cmake/BundledRizin.cmake | 3 ++- cmake/CutterConfig.cmake | 1 - cmake/CutterConfig.cmake.in | 22 +++++++++++++++ cmake/CutterInstallDirs.cmake | 2 +- rizin | 2 +- src/CMakeLists.txt | 27 ++++++++++++------- src/Main.cpp | 2 ++ src/core/MainWindow.h | 2 +- src/plugins/sample-cpp/CMakeLists.txt | 13 +++++++++ src/plugins/sample-cpp/CutterSamplePlugin.cpp | 16 +++++++---- src/plugins/sample-cpp/CutterSamplePlugin.h | 8 +++--- src/plugins/sample-cpp/CutterSamplePlugin.pro | 10 ------- src/widgets/ConsoleWidget.cpp | 1 + 14 files changed, 79 insertions(+), 38 deletions(-) delete mode 100644 cmake/CutterConfig.cmake create mode 100644 cmake/CutterConfig.cmake.in create mode 100644 src/plugins/sample-cpp/CMakeLists.txt delete mode 100644 src/plugins/sample-cpp/CutterSamplePlugin.pro diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c0f30b5..991368ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -57,16 +57,14 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) +set(QT_COMPONENTS Core Widgets Gui Svg Network) if (CUTTER_QT6) set(QT_PREFIX Qt6) + list(APPEND QT_COMPONENTS Core5Compat SvgWidgets OpenGLWidgets) else() set(QT_PREFIX Qt5) endif() - -find_package(${QT_PREFIX} REQUIRED COMPONENTS Core Widgets Gui Svg Network) -if (CUTTER_QT6) - find_package(${QT_PREFIX} REQUIRED COMPONENTS Core5Compat SvgWidgets OpenGLWidgets) -endif() +find_package(${QT_PREFIX} REQUIRED COMPONENTS ${QT_COMPONENTS}) if(CUTTER_ENABLE_PYTHON) find_package(PythonInterp REQUIRED) diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index 10f582b4..4dcf4301 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -57,7 +57,8 @@ target_link_libraries(Rizin INTERFACE ${RZ_LIBS}) target_include_directories(Rizin INTERFACE "$" - "$") + "$" + "$") install(TARGETS Rizin EXPORT CutterTargets) if (WIN32) diff --git a/cmake/CutterConfig.cmake b/cmake/CutterConfig.cmake deleted file mode 100644 index 926efecf..00000000 --- a/cmake/CutterConfig.cmake +++ /dev/null @@ -1 +0,0 @@ -include("${CMAKE_CURRENT_LIST_DIR}/CutterTargets.cmake") \ No newline at end of file diff --git a/cmake/CutterConfig.cmake.in b/cmake/CutterConfig.cmake.in new file mode 100644 index 00000000..cfab9542 --- /dev/null +++ b/cmake/CutterConfig.cmake.in @@ -0,0 +1,22 @@ +@PACKAGE_INIT@ + +set(Cutter_RIZIN_BUNDLED @CUTTER_USE_BUNDLED_RIZIN@) + +include(CMakeFindDependencyMacro) +find_dependency(@QT_PREFIX@ COMPONENTS @QT_COMPONENTS@) +find_dependency(Rizin COMPONENTS Core) + +# Make a best guess for a user location from where plugins can be loaded. +# This can be used in Cutter plugins like +# set(CUTTER_INSTALL_PLUGDIR "${Cutter_USER_PLUGINDIR}" CACHE STRING "Directory to install Cutter plugin into") +# see https://doc.qt.io/qt-5/qstandardpaths.html under AppDataLocation +if(APPLE) + set(Cutter_USER_PLUGINDIR "$ENV{HOME}/Library/Application Support/rizin/cutter/plugins/native") +elseif(WIN32) + file(TO_CMAKE_PATH "$ENV{APPDATA}" Cutter_USER_PLUGINDIR) + set(Cutter_USER_PLUGINDIR "${Cutter_USER_PLUGINDIR}/rizin/cutter/plugins/native") +else() + set(Cutter_USER_PLUGINDIR "$ENV{HOME}/.local/share/rizin/cutter/plugins/native") +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/CutterTargets.cmake") diff --git a/cmake/CutterInstallDirs.cmake b/cmake/CutterInstallDirs.cmake index f7133abc..31873c69 100644 --- a/cmake/CutterInstallDirs.cmake +++ b/cmake/CutterInstallDirs.cmake @@ -20,4 +20,4 @@ else() include(GNUInstallDirs) set(CUTTER_INSTALL_DATADIR "${CMAKE_INSTALL_DATAROOTDIR}/${CUTTER_DIR_NAME}" CACHE PATH "Resource installation directory") endif() -set(ConfigPackageLocation "${CMAKE_INSTALL_LIBDIR}/Cutter" CACHE PATH "Cmake file install location") +set(CUTTER_INSTALL_CONFIGDIR "${CMAKE_INSTALL_LIBDIR}/cmake/Cutter" CACHE PATH "CMake file install location") diff --git a/rizin b/rizin index dd81b662..be48ddcd 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit dd81b6629a45ec3d221042ed9729b50cd3c478c5 +Subproject commit be48ddcd9f0c2023d0e64750426c0476a13d8589 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4601cb96..4fb5d4d4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -558,17 +558,26 @@ install(TARGETS Cutter EXPORT CutterTargets RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}" BUNDLE DESTINATION "." # needs to be tested - ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT Devel -) + ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" COMPONENT Devel) install(EXPORT CutterTargets NAMESPACE Cutter:: - DESTINATION "${ConfigPackageLocation}" + DESTINATION "${CUTTER_INSTALL_CONFIGDIR}" COMPONENT Devel) +include(CMakePackageConfigHelpers) +configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/CutterConfig.cmake.in + "${CMAKE_CURRENT_BINARY_DIR}/CutterConfig.cmake" + INSTALL_DESTINATION "${CUTTER_INSTALL_CONFIGDIR}" + NO_SET_AND_CHECK_MACRO + NO_CHECK_REQUIRED_COMPONENTS_MACRO) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/CutterConfigVersion.cmake" + VERSION "${CUTTER_VERSION_FULL}" + COMPATIBILITY AnyNewerVersion) install(FILES - ../cmake/CutterConfig.cmake - DESTINATION ${ConfigPackageLocation} - COMPONENT Devel -) + "${CMAKE_CURRENT_BINARY_DIR}/CutterConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/CutterConfigVersion.cmake" + DESTINATION ${CUTTER_INSTALL_CONFIGDIR} + COMPONENT Devel) foreach(_file ${HEADER_FILES}) # Can't use target PUBLIC_HEADER option for installing due to multiple directories get_filename_component(_header_dir "${_file}" DIRECTORY) @@ -576,8 +585,8 @@ foreach(_file ${HEADER_FILES}) endforeach() if(UNIX AND NOT APPLE) - install (FILES "img/cutter.svg" - DESTINATION "share/icons/hicolor/scalable/apps/") + install(FILES "img/cutter.svg" + DESTINATION "share/icons/hicolor/scalable/apps/") install(FILES "re.rizin.cutter.desktop" DESTINATION "share/applications" COMPONENT Devel) diff --git a/src/Main.cpp b/src/Main.cpp index b0cef4a0..8cb4347f 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -14,6 +14,8 @@ * @brief Attempt to connect to a parent console and configure outputs. */ #ifdef Q_OS_WIN +#include + static void connectToConsole() { BOOL attached = AttachConsole(ATTACH_PARENT_PROCESS); diff --git a/src/core/MainWindow.h b/src/core/MainWindow.h index dd878062..ce1bdceb 100644 --- a/src/core/MainWindow.h +++ b/src/core/MainWindow.h @@ -60,7 +60,7 @@ namespace Ui { class MainWindow; } -class MainWindow : public QMainWindow +class CUTTER_EXPORT MainWindow : public QMainWindow { Q_OBJECT diff --git a/src/plugins/sample-cpp/CMakeLists.txt b/src/plugins/sample-cpp/CMakeLists.txt new file mode 100644 index 00000000..93e140f5 --- /dev/null +++ b/src/plugins/sample-cpp/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.12) +project(cutter-sample-plugin) + +find_package(Cutter REQUIRED) +set(CUTTER_INSTALL_PLUGDIR "${Cutter_USER_PLUGINDIR}" CACHE STRING "Directory to install Cutter plugin into") + +set(CMAKE_AUTOMOC ON) + +add_library(sample_plugin MODULE + CutterSamplePlugin.h + CutterSamplePlugin.cpp) +target_link_libraries(sample_plugin PRIVATE Cutter::Cutter) +install(TARGETS sample_plugin DESTINATION "${CUTTER_INSTALL_PLUGDIR}") diff --git a/src/plugins/sample-cpp/CutterSamplePlugin.cpp b/src/plugins/sample-cpp/CutterSamplePlugin.cpp index 98c95f70..bb2264b3 100644 --- a/src/plugins/sample-cpp/CutterSamplePlugin.cpp +++ b/src/plugins/sample-cpp/CutterSamplePlugin.cpp @@ -4,9 +4,10 @@ #include #include "CutterSamplePlugin.h" -#include "common/TempConfig.h" -#include "common/Configuration.h" -#include "MainWindow.h" + +#include +#include +#include void CutterSamplePlugin::setupPlugin() {} @@ -56,9 +57,14 @@ void CutterSamplePluginWidget::on_seekChanged(RVA addr) void CutterSamplePluginWidget::on_buttonClicked() { - QString fortune = Core()->cmd("fo").replace("\n", ""); + RzCoreLocked core(Core()); + char *fortune = rz_core_fortune_get_random(core); + if (!fortune) { + return; + } // cmdRaw can be used to execute single raw commands // this is especially good for user-controlled input - QString res = Core()->cmdRaw("?E " + fortune); + QString res = Core()->cmdRaw("?E " + QString::fromUtf8(fortune)); text->setText(res); + rz_mem_free(fortune); } diff --git a/src/plugins/sample-cpp/CutterSamplePlugin.h b/src/plugins/sample-cpp/CutterSamplePlugin.h index 45cbaedb..d0497a0c 100644 --- a/src/plugins/sample-cpp/CutterSamplePlugin.h +++ b/src/plugins/sample-cpp/CutterSamplePlugin.h @@ -1,9 +1,9 @@ #ifndef CUTTERSAMPLEPLUGIN_H #define CUTTERSAMPLEPLUGIN_H -#include -#include -#include "CutterPlugin.h" +#include + +#include class CutterSamplePlugin : public QObject, CutterPlugin { @@ -26,7 +26,7 @@ class CutterSamplePluginWidget : public CutterDockWidget Q_OBJECT public: - explicit CutterSamplePluginWidget(MainWindow *main, QAction *action); + explicit CutterSamplePluginWidget(MainWindow *main); private: QLabel *text; diff --git a/src/plugins/sample-cpp/CutterSamplePlugin.pro b/src/plugins/sample-cpp/CutterSamplePlugin.pro deleted file mode 100644 index c65aca87..00000000 --- a/src/plugins/sample-cpp/CutterSamplePlugin.pro +++ /dev/null @@ -1,10 +0,0 @@ -HEADERS += ../CutterSamplePlugin.h ../CutterPlugin.h -INCLUDEPATH += ../ ../../ ../../core ../../widgets -SOURCES += CutterSamplePlugin.cpp - -QMAKE_CXXFLAGS += $$system("pkg-config --cflags rz_core") - -TEMPLATE = lib -CONFIG += plugin -QT += widgets -TARGET = PluginSample diff --git a/src/widgets/ConsoleWidget.cpp b/src/widgets/ConsoleWidget.cpp index db378068..de0e6892 100644 --- a/src/widgets/ConsoleWidget.cpp +++ b/src/widgets/ConsoleWidget.cpp @@ -17,6 +17,7 @@ #include "WidgetShortcuts.h" #ifdef Q_OS_WIN +# include # include # define dup2 _dup2 # define dup _dup From e3a01d3780392f8f034b3ebbe3a5c98df1d95836 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Thu, 31 Mar 2022 19:34:34 +0200 Subject: [PATCH 096/240] =?UTF-8?q?=E2=80=98memDisp=E2=80=99=20may=20be=20?= =?UTF-8?q?used=20uninitialized=20(#2920)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/menus/DisassemblyContextMenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index c2065c9d..15e23f8c 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -489,7 +489,7 @@ void DisassemblyContextMenu::aboutToShowSlot() // Create structure offset menu if it makes sense QString memBaseReg; // Base register - st64 memDisp; // Displacement + st64 memDisp = 0; // Displacement // Loop through both the operands of the instruction for (const CutterJson operand : instObject["opex"]["operands"]) { From ea519df01e1471b2b3fd4baab8acb173181c6f83 Mon Sep 17 00:00:00 2001 From: billow Date: Sat, 2 Apr 2022 15:44:42 +0800 Subject: [PATCH 097/240] Convert various debug code to C API (#2913) --- src/common/AnalysisTask.cpp | 4 +- src/core/Cutter.cpp | 213 +++++++++++++++++++-------- src/core/Cutter.h | 39 +++-- src/core/CutterDescriptions.h | 4 +- src/dialogs/EditVariablesDialog.cpp | 3 +- src/menus/DecompilerContextMenu.cpp | 2 +- src/menus/DisassemblyContextMenu.cpp | 2 +- src/widgets/DebugActions.cpp | 2 +- src/widgets/ProcessesWidget.cpp | 36 +++-- src/widgets/ProcessesWidget.h | 2 +- src/widgets/ThreadsWidget.cpp | 18 +-- src/widgets/ThreadsWidget.h | 2 +- 12 files changed, 215 insertions(+), 112 deletions(-) diff --git a/src/common/AnalysisTask.cpp b/src/common/AnalysisTask.cpp index 75e90395..dc4a5094 100644 --- a/src/common/AnalysisTask.cpp +++ b/src/common/AnalysisTask.cpp @@ -79,14 +79,14 @@ void AnalysisTask::runTask() if (!options.shellcode.isNull() && options.shellcode.size() / 2 > 0) { log(tr("Loading shellcode...")); - Core()->cmdRaw("wx " + options.shellcode); + rz_core_write_hexpair(core, core->offset, options.shellcode.toStdString().c_str()); } if (options.endian != InitialOptions::Endianness::Auto) { Core()->setEndianness(options.endian == InitialOptions::Endianness::Big); } - Core()->cmdRaw("fs *"); + rz_flag_space_set(core->flags, "*"); if (!options.script.isNull()) { log(tr("Executing script...")); diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 5c9ba1d0..4721ab4f 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -408,7 +408,7 @@ bool CutterCore::isDebugTaskInProgress() return false; } -bool CutterCore::asyncCmdEsil(const char *command, QSharedPointer &task) +bool CutterCore::asyncCmdEsil(const char *command, QSharedPointer &task) { asyncCmd(command, task); @@ -417,7 +417,7 @@ bool CutterCore::asyncCmdEsil(const char *command, QSharedPointer } connect(task.data(), &RizinCmdTask::finished, task.data(), [this, task]() { - QString res = task.data()->getResult(); + QString res = qobject_cast(task.data())->getResult(); if (res.contains(QStringLiteral("[ESIL] Stopped execution in an invalid instruction"))) { msgBox.showMessage("Stopped when attempted to run an invalid instruction. You can " @@ -428,7 +428,7 @@ bool CutterCore::asyncCmdEsil(const char *command, QSharedPointer return true; } -bool CutterCore::asyncCmd(const char *str, QSharedPointer &task) +bool CutterCore::asyncCmd(const char *str, QSharedPointer &task) { if (!task.isNull()) { return false; @@ -438,8 +438,28 @@ bool CutterCore::asyncCmd(const char *str, QSharedPointer &task) RVA offset = core->offset; - task = QSharedPointer(new RizinCmdTask(str, true)); - connect(task.data(), &RizinCmdTask::finished, task.data(), [this, offset, task]() { + task = QSharedPointer(new RizinCmdTask(str, true)); + connect(task.data(), &RizinTask::finished, task.data(), [this, offset, task]() { + CORE_LOCK(); + + if (offset != core->offset) { + updateSeek(); + } + }); + + return true; +} + +bool CutterCore::asyncTask(std::function fcn, QSharedPointer &task) +{ + if (!task.isNull()) { + return false; + } + + CORE_LOCK(); + RVA offset = core->offset; + task = QSharedPointer(new RizinFunctionTask(std::move(fcn), true)); + connect(task.data(), &RizinTask::finished, task.data(), [this, offset, task]() { CORE_LOCK(); if (offset != core->offset) { @@ -819,12 +839,23 @@ void CutterCore::removeString(RVA addr) QString CutterCore::getString(RVA addr) { - return cmdRawAt("ps", addr); + CORE_LOCK(); + char *s = (char *)returnAtSeek( + [&]() { + RzStrStringifyOpt opt = { 0 }; + opt.buffer = core->block; + opt.length = core->blocksize; + opt.encoding = rz_str_guess_encoding_from_buffer(core->block, core->blocksize); + return rz_str_stringify_raw_buffer(&opt, NULL); + }, + addr); + return fromOwnedCharPtr(s); } QString CutterCore::getMetaString(RVA addr) { - return cmdRawAt("Cs.", addr); + CORE_LOCK(); + return rz_meta_get_string(core->analysis, RZ_META_TYPE_STRING, addr); } void CutterCore::setToData(RVA addr, int size, int repeat) @@ -1595,16 +1626,6 @@ AddrRefs CutterCore::getAddrRefs(RVA addr, int depth) return refs; } -CutterJson CutterCore::getProcessThreads(int pid) -{ - if (-1 == pid) { - // Return threads list of the currently debugged PID - return cmdj("dptj"); - } else { - return cmdj("dptj " + QString::number(pid)); - } -} - QVector CutterCore::getHeapChunks(RVA arena_addr) { CORE_LOCK(); @@ -1735,16 +1756,6 @@ bool CutterCore::writeHeapChunk(RzHeapChunkSimple *chunk_simple) return rz_heap_write_chunk(core, chunk_simple); } -CutterJson CutterCore::getChildProcesses(int pid) -{ - // Return the currently debugged process and it's children - if (-1 == pid) { - return cmdj("dpj"); - } - // Return the given pid and it's child processes - return cmdj("dpj " + QString::number(pid)); -} - CutterJson CutterCore::getRegisterValues() { return cmdj("drj"); @@ -1831,7 +1842,12 @@ void CutterCore::setRegister(QString regName, QString regValue) void CutterCore::setCurrentDebugThread(int tid) { - if (!asyncCmd("dpt=" + QString::number(tid), debugTask)) { + if (!asyncTask( + [=](RzCore *core) { + rz_debug_select(core->dbg, core->dbg->pid, tid); + return (void *)NULL; + }, + debugTask)) { return; } @@ -1851,7 +1867,14 @@ void CutterCore::setCurrentDebugThread(int tid) void CutterCore::setCurrentDebugProcess(int pid) { - if (!currentlyDebugging || !asyncCmd("dp=" + QString::number(pid), debugTask)) { + if (!currentlyDebugging + || !asyncTask( + [=](RzCore *core) { + rz_debug_select(core->dbg, pid, core->dbg->tid); + core->dbg->main_pid = pid; + return (void *)NULL; + }, + debugTask)) { return; } @@ -1877,7 +1900,12 @@ void CutterCore::startDebug() } currentlyOpenFile = getConfig("file.path"); - if (!asyncCmd("ood", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_file_reopen_debug(core, ""); + return (void *)NULL; + }, + debugTask)) { return; } @@ -1961,7 +1989,15 @@ void CutterCore::attachRemote(const QString &uri) } // connect to a debugger with the given plugin - asyncCmd("e cfg.debug=true; oodf " + uri, debugTask); + if (!asyncTask( + [&](RzCore *core) { + setConfig("cfg.debug", true); + rz_core_file_reopen_remote_debug(core, uri.toStdString().c_str(), 0); + return (void *)NULL; + }, + debugTask)) { + return; + } emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this, uri]() { @@ -2124,7 +2160,12 @@ void CutterCore::continueDebug() return; } } else { - if (!asyncCmd("dc", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_debug_continue(core->dbg); + return (void *)NULL; + }, + debugTask)) { return; } } @@ -2151,7 +2192,12 @@ void CutterCore::continueBackDebug() return; } } else { - if (!asyncCmd("dcb", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_debug_continue_back(core->dbg); + return (void *)NULL; + }, + debugTask)) { return; } } @@ -2167,22 +2213,26 @@ void CutterCore::continueBackDebug() debugTask->startTask(); } -void CutterCore::continueUntilDebug(QString offset) +void CutterCore::continueUntilDebug(ut64 offset) { if (!currentlyDebugging) { return; } if (currentlyEmulating) { - if (!asyncCmdEsil("aecu " + offset, debugTask)) { + if (!asyncCmdEsil("aecu " + QString::number(offset), debugTask)) { return; } } else { - if (!asyncCmd("dcu " + offset, debugTask)) { + if (!asyncTask( + [=](RzCore *core) { + rz_core_debug_continue_until(core, offset, offset); + return (void *)NULL; + }, + debugTask)) { return; } } - emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this]() { debugTask.clear(); @@ -2190,7 +2240,6 @@ void CutterCore::continueUntilDebug(QString offset) emit refreshCodeViews(); emit debugTaskStateChanged(); }); - debugTask->startTask(); } @@ -2205,7 +2254,12 @@ void CutterCore::continueUntilCall() return; } } else { - if (!asyncCmd("dcc", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_debug_step_one(core, 0); + return (void *)NULL; + }, + debugTask)) { return; } } @@ -2259,7 +2313,12 @@ void CutterCore::stepDebug() return; } } else { - if (!asyncCmd("ds", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_debug_step_one(core, 1); + return (void *)NULL; + }, + debugTask)) { return; } } @@ -2383,7 +2442,13 @@ void CutterCore::startTraceSession() return; } } else { - if (!asyncCmd("dts+", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + core->dbg->session = rz_debug_session_new(); + rz_debug_add_checkpoint(core->dbg); + return (void *)NULL; + }, + debugTask)) { return; } } @@ -2419,7 +2484,13 @@ void CutterCore::stopTraceSession() return; } } else { - if (!asyncCmd("dts-", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_debug_session_free(core->dbg->session); + core->dbg->session = NULL; + return (void *)NULL; + }, + debugTask)) { return; } } @@ -2517,25 +2588,29 @@ void CutterCore::updateBreakpoint(int index, const BreakpointDescription &config void CutterCore::delBreakpoint(RVA addr) { - cmdRaw("db- " + RzAddressString(addr)); + CORE_LOCK(); + rz_bp_del(core->dbg->bp, addr); emit breakpointsChanged(addr); } void CutterCore::delAllBreakpoints() { - cmdRaw("db-*"); + CORE_LOCK(); + rz_bp_del_all(core->dbg->bp); emit refreshCodeViews(); } void CutterCore::enableBreakpoint(RVA addr) { - cmdRaw("dbe " + RzAddressString(addr)); + CORE_LOCK(); + rz_bp_enable(core->dbg->bp, addr, true, 1); emit breakpointsChanged(addr); } void CutterCore::disableBreakpoint(RVA addr) { - cmdRaw("dbd " + RzAddressString(addr)); + CORE_LOCK(); + rz_bp_enable(core->dbg->bp, addr, false, 1); emit breakpointsChanged(addr); } @@ -2631,37 +2706,53 @@ CutterJson CutterCore::getBacktrace() return cmdj("dbtj"); } -QList CutterCore::getAllProcesses() +QList CutterCore::getProcessThreads(int pid = -1) { + CORE_LOCK(); + RzList *list = rz_debug_pids(core->dbg, pid != -1 ? pid : core->dbg->pid); + RzListIter *iter; + RzDebugPid *p; QList ret; - for (CutterJson procObject : cmdj("dplj")) { + CutterRzListForeach (list, iter, RzDebugPid, p) { ProcessDescription proc; - proc.pid = procObject[RJsonKey::pid].toSt64(); - proc.uid = procObject[RJsonKey::uid].toSt64(); - proc.status = procObject[RJsonKey::status].toString(); - proc.path = procObject[RJsonKey::path].toString(); + proc.current = core->dbg->pid == p->pid; + proc.ppid = p->ppid; + proc.pid = p->pid; + proc.uid = p->uid; + proc.status = static_cast(p->status); + proc.path = p->path; ret << proc; } - + rz_list_free(list); return ret; } +QList CutterCore::getAllProcesses() +{ + return getProcessThreads(0); +} + QList CutterCore::getMemoryMap() { + CORE_LOCK(); + RzList *list0 = rz_debug_map_list(core->dbg, false); + RzList *list1 = rz_debug_map_list(core->dbg, true); + rz_list_join(list0, list1); QList ret; - - for (CutterJson memMapObject : cmdj("dmj")) { + RzListIter *it; + RzDebugMap *map; + CutterRzListForeach (list0, it, RzDebugMap, map) { MemoryMapDescription memMap; - memMap.name = memMapObject[RJsonKey::name].toString(); - memMap.fileName = memMapObject[RJsonKey::file].toString(); - memMap.addrStart = memMapObject[RJsonKey::addr].toRVA(); - memMap.addrEnd = memMapObject[RJsonKey::addr_end].toRVA(); - memMap.type = memMapObject[RJsonKey::type].toString(); - memMap.permission = memMapObject[RJsonKey::perm].toString(); + memMap.name = map->name; + memMap.fileName = map->file; + memMap.addrStart = map->addr; + memMap.addrEnd = map->addr_end; + memMap.type = map->user ? "u" : "s"; + memMap.permission = rz_str_rwx_i(map->perm); ret << memMap; } diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 249da7ce..4013f39e 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -24,6 +24,7 @@ class CutterCore; class Decompiler; class RizinTask; class RizinCmdTask; +class RizinFunctionTask; class RizinTaskDialog; #include "common/BasicBlockHighlighter.h" @@ -99,12 +100,19 @@ public: * Once you have setup connections you can start the task with task->startTask() * If you want to seek to an address, you should use CutterCore::seek. */ - bool asyncCmd(const char *str, QSharedPointer &task); - bool asyncCmd(const QString &str, QSharedPointer &task) + bool asyncCmd(const char *str, QSharedPointer &task); + bool asyncCmd(const QString &str, QSharedPointer &task) { return asyncCmd(str.toUtf8().constData(), task); } + /** + * @brief send a task to Rizin + * @param fcn the task you want to execute + * @return execute successful? + */ + bool asyncTask(std::function fcn, QSharedPointer &task); + /** * @brief Execute a Rizin command \a cmd. By nature, the API * is executing raw commands, and thus ignores multiple commands and overcome command @@ -148,6 +156,15 @@ public: seekSilent(oldOffset); } + void *returnAtSeek(std::function fn, RVA address) + { + RVA oldOffset = getOffset(); + seekSilent(address); + void *ret = fn(); + seekSilent(oldOffset); + return ret; + } + CutterJson cmdj(const char *str); CutterJson cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); } CutterJson cmdjAt(const char *str, RVA address); @@ -175,8 +192,8 @@ public: * Once you have setup connections you can start the task with task->startTask() * If you want to seek to an address, you should use CutterCore::seek. */ - bool asyncCmdEsil(const char *command, QSharedPointer &task); - bool asyncCmdEsil(const QString &command, QSharedPointer &task) + bool asyncCmdEsil(const char *command, QSharedPointer &task); + bool asyncCmdEsil(const QString &command, QSharedPointer &task) { return asyncCmdEsil(command.toUtf8().constData(), task); } @@ -431,15 +448,9 @@ public: /** * @brief Get a list of a given process's threads * @param pid The pid of the process, -1 for the currently debugged process - * @return JSON object result of dptj + * @return List of ProcessDescription */ - CutterJson getProcessThreads(int pid); - /** - * @brief Get a list of a given process's child processes - * @param pid The pid of the process, -1 for the currently debugged process - * @return JSON object result of dptj - */ - CutterJson getChildProcesses(int pid); + QList getProcessThreads(int pid); CutterJson getBacktrace(); /** * @brief Get a list of heap chunks @@ -493,7 +504,7 @@ public: void continueBackDebug(); void continueUntilCall(); void continueUntilSyscall(); - void continueUntilDebug(QString offset); + void continueUntilDebug(ut64 offset); void stepDebug(); void stepOverDebug(); void stepOutDebug(); @@ -814,7 +825,7 @@ private: bool iocache = false; BasicInstructionHighlighter biHighlighter; - QSharedPointer debugTask; + QSharedPointer debugTask; RizinTaskDialog *debugTaskDialog; QVector getCutterRCFilePaths() const; diff --git a/src/core/CutterDescriptions.h b/src/core/CutterDescriptions.h index e28894ee..a56f7186 100644 --- a/src/core/CutterDescriptions.h +++ b/src/core/CutterDescriptions.h @@ -339,9 +339,11 @@ struct BreakpointDescription struct ProcessDescription { + bool current; int pid; int uid; - QString status; + int ppid; + RzDebugPidState status; QString path; }; diff --git a/src/dialogs/EditVariablesDialog.cpp b/src/dialogs/EditVariablesDialog.cpp index 6954814a..1f2139ef 100644 --- a/src/dialogs/EditVariablesDialog.cpp +++ b/src/dialogs/EditVariablesDialog.cpp @@ -14,7 +14,8 @@ EditVariablesDialog::EditVariablesDialog(RVA offset, QString initialVar, QWidget connect(ui->dropdownLocalVars, &QComboBox::currentIndexChanged, this, &EditVariablesDialog::updateFields); - QString fcnName = Core()->cmdRawAt("afn.", offset).trimmed(); + RzAnalysisFunction *f = rz_analysis_get_function_at(Core()->core()->analysis, offset); + QString fcnName = f->name; functionAddress = offset; setWindowTitle(tr("Edit Variables in Function: %1").arg(fcnName)); diff --git a/src/menus/DecompilerContextMenu.cpp b/src/menus/DecompilerContextMenu.cpp index d36cf0b7..7113ec68 100644 --- a/src/menus/DecompilerContextMenu.cpp +++ b/src/menus/DecompilerContextMenu.cpp @@ -519,7 +519,7 @@ void DecompilerContextMenu::actionAdvancedBreakpointTriggered() void DecompilerContextMenu::actionContinueUntilTriggered() { - Core()->continueUntilDebug(RzAddressString(offset)); + Core()->continueUntilDebug(offset); } void DecompilerContextMenu::actionSetPCTriggered() diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 15e23f8c..f39bbd79 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -777,7 +777,7 @@ void DisassemblyContextMenu::on_actionAdvancedBreakpoint_triggered() void DisassemblyContextMenu::on_actionContinueUntil_triggered() { - Core()->continueUntilDebug(RzAddressString(offset)); + Core()->continueUntilDebug(offset); } void DisassemblyContextMenu::on_actionSetPC_triggered() diff --git a/src/widgets/DebugActions.cpp b/src/widgets/DebugActions.cpp index 3ed1b877..68d0362c 100644 --- a/src/widgets/DebugActions.cpp +++ b/src/widgets/DebugActions.cpp @@ -281,7 +281,7 @@ void DebugActions::continueUntilMain() return; } } - Core()->continueUntilDebug(QString::number(main_flag->offset)); + Core()->continueUntilDebug(main_flag->offset); } void DebugActions::attachRemoteDebugger() diff --git a/src/widgets/ProcessesWidget.cpp b/src/widgets/ProcessesWidget.cpp index b8e12435..2a9477f8 100644 --- a/src/widgets/ProcessesWidget.cpp +++ b/src/widgets/ProcessesWidget.cpp @@ -84,9 +84,9 @@ void ProcessesWidget::updateContents() } } -QString ProcessesWidget::translateStatus(QString status) +QString ProcessesWidget::translateStatus(const char status) { - switch (status.toStdString().c_str()[0]) { + switch (status) { case RZ_DBG_PROC_STOP: return "Stopped"; case RZ_DBG_PROC_RUN: @@ -109,12 +109,12 @@ void ProcessesWidget::setProcessesGrid() int i = 0; QFont font; - for (CutterJson processesItem : Core()->getChildProcesses(DEBUGGED_PID)) { - st64 pid = processesItem["pid"].toSt64(); - st64 uid = processesItem["uid"].toSt64(); - QString status = translateStatus(processesItem["status"].toString()); - QString path = processesItem["path"].toString(); - bool current = processesItem["current"].toBool(); + for (const auto &processesItem : Core()->getProcessThreads(DEBUGGED_PID)) { + st64 pid = processesItem.pid; + st64 uid = processesItem.uid; + QString status = translateStatus(processesItem.status); + QString path = processesItem.path; + bool current = processesItem.current; // Use bold font to highlight active thread font.setBold(current); @@ -143,7 +143,6 @@ void ProcessesWidget::setProcessesGrid() modelFilter->setSourceModel(modelProcesses); ui->viewProcesses->resizeColumnsToContents(); - ; } void ProcessesWidget::fontsUpdatedSlot() @@ -157,24 +156,23 @@ void ProcessesWidget::onActivated(const QModelIndex &index) return; int pid = modelFilter->data(index.sibling(index.row(), COLUMN_PID)).toInt(); - // Verify that the selected pid is still in the processes list since dp= will // attach to any given id. If it isn't found simply update the UI. - for (CutterJson value : Core()->getChildProcesses(DEBUGGED_PID)) { - QString status = value["status"].toString(); - if (pid == value["pid"].toSt64()) { - if (QString(QChar(RZ_DBG_PROC_ZOMBIE)) == status - || QString(QChar(RZ_DBG_PROC_DEAD)) == status) { - QMessageBox msgBox; + for (const auto &value : Core()->getAllProcesses()) { + if (pid == value.pid) { + QMessageBox msgBox; + switch (value.status) { + case RZ_DBG_PROC_ZOMBIE: + case RZ_DBG_PROC_DEAD: msgBox.setText(tr("Unable to switch to the requested process.")); msgBox.exec(); - } else { + break; + default: Core()->setCurrentDebugProcess(pid); + break; } - break; } } - updateContents(); } diff --git a/src/widgets/ProcessesWidget.h b/src/widgets/ProcessesWidget.h index 80e89007..fcc9db80 100644 --- a/src/widgets/ProcessesWidget.h +++ b/src/widgets/ProcessesWidget.h @@ -41,7 +41,7 @@ private slots: void onActivated(const QModelIndex &index); private: - QString translateStatus(QString status); + QString translateStatus(const char status); std::unique_ptr ui; QStandardItemModel *modelProcesses; ProcessesFilterModel *modelFilter; diff --git a/src/widgets/ThreadsWidget.cpp b/src/widgets/ThreadsWidget.cpp index 6cdde089..d9149108 100644 --- a/src/widgets/ThreadsWidget.cpp +++ b/src/widgets/ThreadsWidget.cpp @@ -82,9 +82,9 @@ void ThreadsWidget::updateContents() } } -QString ThreadsWidget::translateStatus(QString status) +QString ThreadsWidget::translateStatus(const char status) { - switch (status.toStdString().c_str()[0]) { + switch (status) { case RZ_DBG_PROC_STOP: return "Stopped"; case RZ_DBG_PROC_RUN: @@ -107,11 +107,11 @@ void ThreadsWidget::setThreadsGrid() int i = 0; QFont font; - for (CutterJson threadsItem : Core()->getProcessThreads(DEBUGGED_PID)) { - st64 pid = threadsItem["pid"].toSt64(); - QString status = translateStatus(threadsItem["status"].toString()); - QString path = threadsItem["path"].toString(); - bool current = threadsItem["current"].toBool(); + for (const auto &threadsItem : Core()->getProcessThreads(DEBUGGED_PID)) { + st64 pid = threadsItem.pid; + QString status = translateStatus(threadsItem.status); + QString path = threadsItem.path; + bool current = threadsItem.current; // Use bold font to highlight active thread font.setBold(current); QStandardItem *rowPid = new QStandardItem(QString::number(pid)); @@ -150,8 +150,8 @@ void ThreadsWidget::onActivated(const QModelIndex &index) // Verify that the selected tid is still in the threads list since dpt= will // attach to any given id. If it isn't found simply update the UI. - for (CutterJson value : Core()->getProcessThreads(DEBUGGED_PID)) { - if (tid == value["pid"].toSt64()) { + for (const auto &value : Core()->getProcessThreads(DEBUGGED_PID)) { + if (tid == value.pid) { Core()->setCurrentDebugThread(tid); break; } diff --git a/src/widgets/ThreadsWidget.h b/src/widgets/ThreadsWidget.h index 8d9c6a0e..259c919d 100644 --- a/src/widgets/ThreadsWidget.h +++ b/src/widgets/ThreadsWidget.h @@ -41,7 +41,7 @@ private slots: void onActivated(const QModelIndex &index); private: - QString translateStatus(QString status); + QString translateStatus(const char status); std::unique_ptr ui; QStandardItemModel *modelThreads; ThreadsFilterModel *modelFilter; From aed42d7300c38c8c938efaf930f4dba2752241a1 Mon Sep 17 00:00:00 2001 From: tcoyvwac <53616399+tcoyvwac@users.noreply.github.com> Date: Sat, 2 Apr 2022 20:29:50 +0200 Subject: [PATCH 098/240] widgets: redundant return-break (#2922) Removed consecutive return-break statements. --- src/widgets/GraphView.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/widgets/GraphView.cpp b/src/widgets/GraphView.cpp index 1cd9b497..95b81348 100644 --- a/src/widgets/GraphView.cpp +++ b/src/widgets/GraphView.cpp @@ -664,13 +664,11 @@ void GraphView::mousePressEvent(QMouseEvent *event) showBlock(blocks[edge.target]); // TODO: Callback to child return; - break; } if (checkPointClicked(end, pos.x(), pos.y(), true)) { showBlock(block); // TODO: Callback to child return; - break; } } } From 99c58718ec9d35ff78bd15421bb92af5497ba51f Mon Sep 17 00:00:00 2001 From: Islam Bassuni Date: Sun, 3 Apr 2022 16:50:14 +0200 Subject: [PATCH 099/240] Added report issue button in "About" window (#2908) --- src/dialogs/AboutDialog.cpp | 6 + src/dialogs/AboutDialog.h | 1 + src/dialogs/AboutDialog.ui | 256 +++++++++++++++++++++--------------- 3 files changed, 159 insertions(+), 104 deletions(-) diff --git a/src/dialogs/AboutDialog.cpp b/src/dialogs/AboutDialog.cpp index d332cb29..d60a5566 100644 --- a/src/dialogs/AboutDialog.cpp +++ b/src/dialogs/AboutDialog.cpp @@ -5,6 +5,8 @@ #include "ui_AboutDialog.h" #include "RizinPluginsDialog.h" #include "common/Configuration.h" +#include "common/BugReporting.h" + #include #include @@ -85,6 +87,10 @@ void AboutDialog::on_showPluginsButton_clicked() RizinPluginsDialog dialog(this); dialog.exec(); } +void AboutDialog::on_Issue_clicked() +{ + openIssue(); +} void AboutDialog::on_checkForUpdatesButton_clicked() { diff --git a/src/dialogs/AboutDialog.h b/src/dialogs/AboutDialog.h index 2d3ae342..c21baea5 100644 --- a/src/dialogs/AboutDialog.h +++ b/src/dialogs/AboutDialog.h @@ -21,6 +21,7 @@ private slots: void on_buttonBox_rejected(); void on_showVersionButton_clicked(); void on_showPluginsButton_clicked(); + void on_Issue_clicked(); /** * @fn AboutDialog::on_checkForUpdatesButton_clicked() diff --git a/src/dialogs/AboutDialog.ui b/src/dialogs/AboutDialog.ui index e6023527..13742312 100644 --- a/src/dialogs/AboutDialog.ui +++ b/src/dialogs/AboutDialog.ui @@ -6,8 +6,8 @@ 0 0 - 570 - 393 + 935 + 554 @@ -15,6 +15,121 @@ + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + QDialogButtonBox::Close + + + + + + + 5 + + + 15 + + + + + + 0 + 0 + + + + Check for updates on start + + + + + + + + 0 + 0 + + + + Check for updates + + + + + + + + 0 + 0 + + + + <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">Cutter is a free and open-source reverse engineering platform powered by Rizin</span></p><p align="center"><span style=" font-size:11pt;">Read more on </span><a href="https://cutter.re"><span style=" text-decoration: underline; color:#2980b9;">cutter.re</span></a></p></body></html> + + + + + + + <html><head/><body><p><span style=" font-size:28pt; font-weight:600;">Cutter</span></p></body></html> + + + + + + + + 0 + 0 + + + + Report an issue + + + + + + + + 0 + 0 + + + + Show Rizin plugin information + + + + + + + + 0 + 0 + + + + Show version information + + + + + + @@ -42,111 +157,40 @@ - - - - QDialogButtonBox::Close + + + + true + + + + 0 + 0 + + + + + 96 + 96 + + + + + 96 + 96 + + + + Qt::NoFocus + + + Qt::DefaultContextMenu + + + 0 - - - - 5 - - - 15 - - - - - - 0 - 0 - - - - Check for updates on start - - - - - - - - 0 - 0 - - - - Check for updates - - - - - - - - 0 - 0 - - - - Show version information - - - - - - - - 0 - 0 - - - - Show Rizin plugin information - - - - - - - - 0 - 0 - - - - <html><head/><body><p align="center"><span style=" font-size:11pt; font-weight:600;">Cutter is a free and open-source reverse engineering platform powered by Rizin</span></p><p align="center"><span style=" font-size:11pt;">Read more on </span><a href="https://cutter.re"><span style=" text-decoration: underline; color:#2980b9;">cutter.re</span></a></p></body></html> - - - - - - - <html><head/><body><p><span style=" font-size:28pt; font-weight:600;">Cutter</span></p></body></html> - - - - - - - - 96 - 96 - - - - - 96 - 96 - - - - - - @@ -159,4 +203,8 @@ + + signal1() + on_reportIssueButton_clicked() + From 243eded2431f2d1bb7220c1117495ae9429249ae Mon Sep 17 00:00:00 2001 From: rgnter <32541639+rgnter@users.noreply.github.com> Date: Sun, 3 Apr 2022 20:28:45 +0200 Subject: [PATCH 100/240] Fixed a segfault during debugging with gdbserver (#2830) Fixes issue #2829 --- src/widgets/DebugActions.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/widgets/DebugActions.cpp b/src/widgets/DebugActions.cpp index 68d0362c..8745cb86 100644 --- a/src/widgets/DebugActions.cpp +++ b/src/widgets/DebugActions.cpp @@ -297,6 +297,10 @@ void DebugActions::attachRemoteDebugger() void DebugActions::onAttachedRemoteDebugger(bool successfully) { + // TODO(#2829): Investigate why this is happening + if (remoteDialog == nullptr) + return; + if (!successfully) { QMessageBox msgBox; msgBox.setText(tr("Error connecting.")); From 861c7846003e9fb5b72dc78e4f5e7234532b6995 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Tue, 5 Apr 2022 11:35:45 +0200 Subject: [PATCH 101/240] Adds support for RZ_SIGDB path and fixes sorting on some columns (#2923) --- src/core/Cutter.cpp | 35 +++++++++++++++++++++++++---------- src/widgets/FlirtWidget.cpp | 4 ++-- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 4721ab4f..b11c5ebf 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3054,19 +3054,10 @@ QList CutterCore::getAllHeaders() return ret; } -QList CutterCore::getSignaturesDB() +static void sigdb_insert_element_into_qlist(RzList *list, QList &sigdb) { - CORE_LOCK(); - QList sigdb; - const char *sigdb_path = rz_config_get(core->config, "flirt.sigdb.path"); - if (RZ_STR_ISEMPTY(sigdb_path)) { - return sigdb; - } - - RzList *list = rz_sign_sigdb_load_database(sigdb_path, true); void *ptr = NULL; RzListIter *iter = NULL; - rz_list_foreach(list, iter, ptr) { RzSigDBEntry *sig = static_cast(ptr); @@ -3081,6 +3072,30 @@ QList CutterCore::getSignaturesDB() flirt.arch_bits = QString::number(sig->arch_bits); sigdb << flirt; } + rz_list_free(list); +} + +QList CutterCore::getSignaturesDB() +{ + CORE_LOCK(); + QList sigdb; + RzList *list = nullptr; + + char *system_sigdb = rz_path_system(RZ_SIGDB); + if (RZ_STR_ISNOTEMPTY(system_sigdb) && rz_file_is_directory(system_sigdb)) { + list = rz_sign_sigdb_load_database(system_sigdb, true); + sigdb_insert_element_into_qlist(list, sigdb); + } + free(system_sigdb); + + const char *sigdb_path = rz_config_get(core->config, "flirt.sigdb.path"); + if (RZ_STR_ISEMPTY(sigdb_path)) { + return sigdb; + } + + list = rz_sign_sigdb_load_database(sigdb_path, true); + sigdb_insert_element_into_qlist(list, sigdb); + return sigdb; } diff --git a/src/widgets/FlirtWidget.cpp b/src/widgets/FlirtWidget.cpp index 61d43d87..874a63e3 100644 --- a/src/widgets/FlirtWidget.cpp +++ b/src/widgets/FlirtWidget.cpp @@ -107,9 +107,9 @@ bool FlirtProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right case FlirtModel::ArchNameColumn: return leftEntry.arch_name < rightEntry.arch_name; case FlirtModel::ArchBitsColumn: - return leftEntry.arch_bits < rightEntry.arch_bits; + return leftEntry.arch_bits.toULongLong() < rightEntry.arch_bits.toULongLong(); case FlirtModel::NumModulesColumn: - return leftEntry.n_modules < rightEntry.n_modules; + return leftEntry.n_modules.toULongLong() < rightEntry.n_modules.toULongLong(); case FlirtModel::NameColumn: return leftEntry.base_name < rightEntry.base_name; case FlirtModel::DetailsColumn: From de5c1a5154ca2c150aa3b70e66f1664d86f323de Mon Sep 17 00:00:00 2001 From: billow Date: Sun, 10 Apr 2022 11:43:42 +0800 Subject: [PATCH 102/240] Convert from Rizin commands to the API for `w` (#2926) --- src/common/IOModesController.cpp | 2 +- src/core/Cutter.cpp | 13 +++++++++++-- src/core/Cutter.h | 4 ++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/common/IOModesController.cpp b/src/common/IOModesController.cpp index 88378c10..26f0801f 100644 --- a/src/common/IOModesController.cpp +++ b/src/common/IOModesController.cpp @@ -100,7 +100,7 @@ bool IOModesController::askCommitUnsavedChanges() if (ret == QMessageBox::Save) { Core()->commitWriteCache(); } else if (ret == QMessageBox::Discard) { - Core()->cmdRaw("wcr"); + Core()->resetWriteCache(); emit Core()->refreshCodeViews(); } else if (ret == QMessageBox::Cancel) { return false; diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index b11c5ebf..bd801a0e 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -4126,18 +4126,27 @@ bool CutterCore::isIOCacheEnabled() const void CutterCore::commitWriteCache() { + CORE_LOCK(); // Temporarily disable cache mode TempConfig tempConfig; tempConfig.set("io.cache", false); if (!isWriteModeEnabled()) { cmdRaw("oo+"); - cmdRaw("wci"); + rz_io_cache_commit(core->io, 0, UT64_MAX); + rz_core_block_read(core); cmdRaw("oo"); } else { - cmdRaw("wci"); + rz_io_cache_commit(core->io, 0, UT64_MAX); + rz_core_block_read(core); } } +void CutterCore::resetWriteCache() +{ + CORE_LOCK(); + rz_io_cache_reset(core->io, core->io->cached); +} + // Enable or disable write-mode. Avoid unecessary changes if not need. void CutterCore::setWriteMode(bool enabled) { diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 4013f39e..f36796a4 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -721,6 +721,10 @@ public: * @brief Commit write cache to the file on disk. */ void commitWriteCache(); + /** + * @brief Reset write cache. + */ + void resetWriteCache(); /** * @brief Enable or disable Write mode. When the file is opened in write mode, any changes to it From d2243006e275760004729c8a9ebf2113a5bd0c66 Mon Sep 17 00:00:00 2001 From: Islam Bassuni Date: Wed, 13 Apr 2022 06:50:57 +0200 Subject: [PATCH 103/240] Created adding comments option inside Hexdump. (#2927) --- src/widgets/HexWidget.cpp | 38 ++++++++++++++++++++++++++++++++++++++ src/widgets/HexWidget.h | 5 +++++ 2 files changed, 43 insertions(+) diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index 39d9d2e2..b02a0e12 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -2,6 +2,7 @@ #include "Cutter.h" #include "Configuration.h" #include "dialogs/WriteCommandsDialogs.h" +#include "dialogs/CommentsDialog.h" #include #include @@ -120,6 +121,19 @@ HexWidget::HexWidget(QWidget *parent) connect(actionCopyAddress, &QAction::triggered, this, &HexWidget::copyAddress); addAction(actionCopyAddress); + // Add comment option + actionComment = new QAction(tr("Add Comment"), this); + actionComment->setShortcutContext(Qt::ShortcutContext::WidgetWithChildrenShortcut); + actionComment->setShortcut(Qt::Key_Semicolon); + connect(actionComment, &QAction::triggered, this, &HexWidget::on_actionAddComment_triggered); + addAction(actionComment); + + // delete comment option + actionDeleteComment = new QAction(tr("Delete Comment"), this); + actionDeleteComment->setShortcutContext(Qt::ShortcutContext::WidgetWithChildrenShortcut); + connect(actionDeleteComment, &QAction::triggered, this, &HexWidget::on_actionDeleteComment_triggered); + addAction(actionDeleteComment); + actionSelectRange = new QAction(tr("Select range"), this); connect(actionSelectRange, &QAction::triggered, this, [this]() { rangeDialog.open(cursor.address); }); @@ -620,6 +634,16 @@ void HexWidget::contextMenuEvent(QContextMenuEvent *event) actionCopyAddress->setDisabled(disable); }; + QString comment = Core()->getCommentAt(cursor.address); + + if (comment.isNull() || comment.isEmpty()) { + actionDeleteComment->setVisible(false); + actionComment->setText(tr("Add Comment")); + } else { + actionDeleteComment->setVisible(true); + actionComment->setText(tr("Edit Comment")); + } + QMenu *menu = new QMenu(); QMenu *sizeMenu = menu->addMenu(tr("Item size:")); sizeMenu->addActions(actionsItemSize); @@ -689,6 +713,20 @@ void HexWidget::copyAddress() clipboard->setText(RzAddressString(addr)); } +//slot for add comment action +void HexWidget::on_actionAddComment_triggered() +{ + uint64_t addr = cursor.address; + CommentsDialog::addOrEditComment(addr, this); +} + +//slot for deleting comment action +void HexWidget::on_actionDeleteComment_triggered() +{ + uint64_t addr = cursor.address; + Core()->delComment(addr); +} + void HexWidget::onRangeDialogAccepted() { if (rangeDialog.empty()) { diff --git a/src/widgets/HexWidget.h b/src/widgets/HexWidget.h index 5a6a15f0..b46f0574 100644 --- a/src/widgets/HexWidget.h +++ b/src/widgets/HexWidget.h @@ -311,6 +311,8 @@ private slots: void copy(); void copyAddress(); void onRangeDialogAccepted(); + void on_actionAddComment_triggered(); + void on_actionDeleteComment_triggered(); // Write command slots void w_writeString(); @@ -475,6 +477,9 @@ private: QAction *actionHexPairs; QAction *actionCopy; QAction *actionCopyAddress; + QAction *actionComment; + QAction *actionDeleteComment; + QAction *actionSetFlag; QAction *actionSelectRange; QList actionsWriteString; QList actionsWriteOther; From 8cb4f867fa876253c75057c8664572fa4a0a94c5 Mon Sep 17 00:00:00 2001 From: staz <74452129+alyanser@users.noreply.github.com> Date: Sat, 7 May 2022 16:59:46 +0500 Subject: [PATCH 104/240] Fixed an invalid index check (#2937) --- src/widgets/GlibcHeapWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/GlibcHeapWidget.cpp b/src/widgets/GlibcHeapWidget.cpp index 47278fa6..a06f6a77 100644 --- a/src/widgets/GlibcHeapWidget.cpp +++ b/src/widgets/GlibcHeapWidget.cpp @@ -71,7 +71,7 @@ void GlibcHeapWidget::updateArenas() } // check if arenas reduced or invalid index and restore the previously selected arena - if (arenaSelectorView->count() < currentIndex || currentIndex == -1) { + if (arenaSelectorView->count() <= currentIndex || currentIndex == -1) { currentIndex = 0; } arenaSelectorView->setCurrentIndex(currentIndex); From 6f61d0d7d84bef37505eacd31d85825701dc96b0 Mon Sep 17 00:00:00 2001 From: Jakob Zielinski <60484807+jsz6389@users.noreply.github.com> Date: Sat, 7 May 2022 08:01:10 -0400 Subject: [PATCH 105/240] Search button disabled and button text changed while search is occurring (#2928) --- src/widgets/SearchWidget.cpp | 17 +++++++++++++++++ src/widgets/SearchWidget.h | 2 ++ 2 files changed, 19 insertions(+) diff --git a/src/widgets/SearchWidget.cpp b/src/widgets/SearchWidget.cpp index ae3c419b..fc5e5d43 100644 --- a/src/widgets/SearchWidget.cpp +++ b/src/widgets/SearchWidget.cpp @@ -195,14 +195,18 @@ SearchWidget::SearchWidget(MainWindow *main) : CutterDockWidget(main), ui(new Ui QShortcut *enter_press = new QShortcut(QKeySequence(Qt::Key_Return), this); connect(enter_press, &QShortcut::activated, this, [this]() { + disableSearch(); refreshSearch(); checkSearchResultEmpty(); + enableSearch(); }); enter_press->setContext(Qt::WidgetWithChildrenShortcut); connect(ui->searchButton, &QAbstractButton::clicked, this, [this]() { + disableSearch(); refreshSearch(); checkSearchResultEmpty(); + enableSearch(); }); connect(ui->searchspaceCombo, @@ -310,3 +314,16 @@ void SearchWidget::updatePlaceholderText(int index) ui->filterLineEdit->setPlaceholderText("jmp rax"); } } + +void SearchWidget::disableSearch() +{ + ui->searchButton->setEnabled(false); + ui->searchButton->setText("Searching..."); + qApp->processEvents(); +} + +void SearchWidget::enableSearch() +{ + ui->searchButton->setEnabled(true); + ui->searchButton->setText("Search"); +} diff --git a/src/widgets/SearchWidget.h b/src/widgets/SearchWidget.h index 8da8b25b..08a9fc14 100644 --- a/src/widgets/SearchWidget.h +++ b/src/widgets/SearchWidget.h @@ -77,6 +77,8 @@ private: void refreshSearch(); void checkSearchResultEmpty(); + void enableSearch(); + void disableSearch(); void setScrollMode(); void updatePlaceholderText(int index); }; From bdeacabffb229002c9fead24e8707d56f0f1bb05 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Sun, 8 May 2022 14:17:52 +0200 Subject: [PATCH 106/240] Replace afcf with C api. (#2940) --- src/core/Cutter.cpp | 11 ++++++++++- src/widgets/GraphWidget.cpp | 8 +++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index bd801a0e..8759c04c 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1266,7 +1266,16 @@ RzAnalysisFunction *CutterCore::functionIn(ut64 addr) RzAnalysisFunction *CutterCore::functionAt(ut64 addr) { CORE_LOCK(); - return rz_analysis_get_function_at(core->analysis, addr); + RzAnalysisFunction *fcn = rz_analysis_get_function_at(core->analysis, addr); + if (fcn) { + return fcn; + } + RzList *list = rz_analysis_get_functions_in(core->analysis, addr); + if (rz_list_length(list) == 1) { + fcn = static_cast(rz_list_first(list)); + } + rz_list_free(list); + return fcn; } /** diff --git a/src/widgets/GraphWidget.cpp b/src/widgets/GraphWidget.cpp index 046babe0..f4b2b43e 100644 --- a/src/widgets/GraphWidget.cpp +++ b/src/widgets/GraphWidget.cpp @@ -84,11 +84,13 @@ QString GraphWidget::getWidgetType() void GraphWidget::prepareHeader() { - QString afcf = Core()->cmdRawAt("afcf", seekable->getOffset()).trimmed(); - if (afcf.isEmpty()) { + RzAnalysisFunction *f = Core()->functionAt(seekable->getOffset()); + char *str = f ? rz_analysis_function_get_signature(f) : nullptr; + if (!str) { header->hide(); return; } header->show(); - header->setText(afcf); + header->setText(str); + free(str); } From 5f376f55dba84dac5f5d885fd91fb43c18fe5f09 Mon Sep 17 00:00:00 2001 From: Paul I Date: Thu, 12 May 2022 17:55:55 +0300 Subject: [PATCH 107/240] Revert changes in functionAt (#2941) --- src/core/Cutter.cpp | 11 +---------- src/widgets/GraphWidget.cpp | 2 +- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 8759c04c..bd801a0e 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1266,16 +1266,7 @@ RzAnalysisFunction *CutterCore::functionIn(ut64 addr) RzAnalysisFunction *CutterCore::functionAt(ut64 addr) { CORE_LOCK(); - RzAnalysisFunction *fcn = rz_analysis_get_function_at(core->analysis, addr); - if (fcn) { - return fcn; - } - RzList *list = rz_analysis_get_functions_in(core->analysis, addr); - if (rz_list_length(list) == 1) { - fcn = static_cast(rz_list_first(list)); - } - rz_list_free(list); - return fcn; + return rz_analysis_get_function_at(core->analysis, addr); } /** diff --git a/src/widgets/GraphWidget.cpp b/src/widgets/GraphWidget.cpp index f4b2b43e..beec0644 100644 --- a/src/widgets/GraphWidget.cpp +++ b/src/widgets/GraphWidget.cpp @@ -84,7 +84,7 @@ QString GraphWidget::getWidgetType() void GraphWidget::prepareHeader() { - RzAnalysisFunction *f = Core()->functionAt(seekable->getOffset()); + RzAnalysisFunction *f = Core()->functionIn(seekable->getOffset()); char *str = f ? rz_analysis_function_get_signature(f) : nullptr; if (!str) { header->hide(); From 3d39cf625fdd7294a41d4867f677f6762e726446 Mon Sep 17 00:00:00 2001 From: billow Date: Sat, 14 May 2022 17:03:59 +0800 Subject: [PATCH 108/240] convert to api for `aoj` --- rizin | 2 +- src/core/Cutter.cpp | 38 +++++++++++++++++++++++++--- src/menus/DisassemblyContextMenu.cpp | 34 +++++++++++++++++-------- 3 files changed, 60 insertions(+), 14 deletions(-) diff --git a/rizin b/rizin index be48ddcd..a1c2ed18 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit be48ddcd9f0c2023d0e64750426c0476a13d8589 +Subproject commit a1c2ed18d762d3641e6690e0cb6b58b45f1c3609 diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index bd801a0e..bcb9b728 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -746,12 +746,32 @@ void CutterCore::delFlag(const QString &name) QString CutterCore::getInstructionBytes(RVA addr) { - return cmdj("aoj @ " + RzAddressString(addr)).first()[RJsonKey::bytes].toString(); + auto ret = (char *)Core()->returnAtSeek( + [&]() { + CORE_LOCK(); + RzPVector *vec = rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); + auto *ab = static_cast(rz_pvector_head(vec)); + char *str = strdup(ab->bytes); + rz_pvector_free(vec); + return str; + }, + addr); + return fromOwnedCharPtr(ret); } QString CutterCore::getInstructionOpcode(RVA addr) { - return cmdj("aoj @ " + RzAddressString(addr)).first()[RJsonKey::opcode].toString(); + auto ret = (char *)Core()->returnAtSeek( + [&]() { + CORE_LOCK(); + RzPVector *vec = rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); + auto *ab = static_cast(rz_pvector_head(vec)); + char *str = strdup(ab->opcode); + rz_pvector_free(vec); + return str; + }, + addr); + return fromOwnedCharPtr(ret); } void CutterCore::editInstruction(RVA addr, const QString &inst) @@ -1358,7 +1378,19 @@ CutterJson CutterCore::getRegistersInfo() RVA CutterCore::getOffsetJump(RVA addr) { - return cmdj("aoj @" + QString::number(addr)).first().toRVA(); + auto rva = (RVA *)Core()->returnAtSeek( + [&]() { + CORE_LOCK(); + RzPVector *vec = rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); + auto *ab = static_cast(rz_pvector_head(vec)); + RVA *rva = new RVA(ab->op->jump); + rz_pvector_free(vec); + return rva; + }, + addr); + RVA ret = *rva; + delete rva; + return ret; } QList CutterCore::getDecompilers() diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index f39bbd79..2f6c6d66 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -482,8 +482,15 @@ void DisassemblyContextMenu::setupRenaming() void DisassemblyContextMenu::aboutToShowSlot() { // check if set immediate base menu makes sense - CutterJson instObject = Core()->cmdj("aoj @ " + QString::number(offset)).first(); - bool immBase = instObject["val"].valid() || instObject["ptr"].valid(); + RzPVector *vec = (RzPVector *)Core()->returnAtSeek( + [&]() { + RzCoreLocked core(Core()); + return rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); + }, + offset); + auto *ab = static_cast(rz_pvector_head(vec)); + + bool immBase = ab && ab->op && (ab->op->val || ab->op->ptr); setBaseMenu->menuAction()->setVisible(immBase); setBitsMenu->menuAction()->setVisible(true); @@ -491,17 +498,24 @@ void DisassemblyContextMenu::aboutToShowSlot() QString memBaseReg; // Base register st64 memDisp = 0; // Displacement - // Loop through both the operands of the instruction - for (const CutterJson operand : instObject["opex"]["operands"]) { - if (operand["type"].toString() == "mem" && !operand["base"].toString().contains("bp") - && operand["disp"].toSt64() > 0) { + if (ab && ab->op) { + const char *opexstr = RZ_STRBUF_SAFEGET(&ab->op->opex); + CutterJson operands = Core()->parseJson(strdup(opexstr), nullptr); - // The current operand is the one which has an immediate displacement - memBaseReg = operand["base"].toString(); - memDisp = operand["disp"].toSt64(); - break; + // Loop through both the operands of the instruction + for (const CutterJson operand : operands) { + if (operand["type"].toString() == "mem" && !operand["base"].toString().contains("bp") + && operand["disp"].toSt64() > 0) { + + // The current operand is the one which has an immediate displacement + memBaseReg = operand["base"].toString(); + memDisp = operand["disp"].toSt64(); + break; + } } } + rz_pvector_free(vec); + if (memBaseReg.isEmpty()) { // hide structure offset menu structureOffsetMenu->menuAction()->setVisible(false); From d6ce8048c5f58998a324239df711e29d4ba10b29 Mon Sep 17 00:00:00 2001 From: billow Date: Sat, 14 May 2022 17:08:52 +0800 Subject: [PATCH 109/240] convert to api for `aht` --- src/core/Cutter.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index bcb9b728..ee9fbf9d 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -951,7 +951,12 @@ void CutterCore::applyStructureOffset(const QString &structureOffset, RVA offset offset = getOffset(); } - this->cmdRawAt("aht " + structureOffset, offset); + applyAtSeek( + [&]() { + CORE_LOCK(); + rz_core_analysis_hint_set_offset(core, structureOffset.toUtf8().constData()); + }, + offset); emit instructionChanged(offset); } From c0f80a2628ab20097fbae90f9561e10c22fc513d Mon Sep 17 00:00:00 2001 From: billow Date: Sat, 14 May 2022 19:13:45 +0800 Subject: [PATCH 110/240] convert to api for `dr` --- src/core/Cutter.cpp | 92 ++++++++++++++++-------------- src/core/Cutter.h | 4 +- src/widgets/RegisterRefsWidget.cpp | 2 +- src/widgets/StackWidget.cpp | 4 +- 4 files changed, 55 insertions(+), 47 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index ee9fbf9d..44a79343 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -127,6 +127,11 @@ static QString fromOwnedCharPtr(char *str) return result; } +static bool reg_sync(RzCore *core, RzRegisterType type, bool write) +{ + return rz_debug_reg_sync(core->dbg, type, write); +} + RzCoreLocked::RzCoreLocked(CutterCore *core) : core(core) { core->coreMutex.lock(); @@ -1376,11 +1381,6 @@ void CutterCore::createFunctionAt(RVA addr, QString name) emit functionsChanged(); } -CutterJson CutterCore::getRegistersInfo() -{ - return cmdj("aeafj"); -} - RVA CutterCore::getOffsetJump(RVA addr) { auto rva = (RVA *)Core()->returnAtSeek( @@ -1448,20 +1448,20 @@ static inline const QString appendVar(QString &dst, const QString val, const QSt return val; } -RefDescription CutterCore::formatRefDesc(const AddrRefs &refItem) +RefDescription CutterCore::formatRefDesc(const QSharedPointer &refItem) { RefDescription desc; - if (refItem.addr == RVA_INVALID) { + if (refItem->addr == RVA_INVALID) { return desc; } - QString str = refItem.string; + QString str = refItem->string; if (!str.isEmpty()) { desc.ref = str; desc.refColor = ConfigColor("comment"); } else { - QSharedPointer cursor(&refItem); + QSharedPointer cursor(refItem); QString type, string; while (true) { desc.ref += " ->"; @@ -1508,15 +1508,21 @@ QList CutterCore::getRegisterRefs(int depth) return ret; } - CutterJson registers = cmdj("drj"); - for (CutterJson value : registers) { + CORE_LOCK(); + RzList *ritems = rz_core_reg_filter_items_sync(core, core->dbg->reg, reg_sync, nullptr); + if (!ritems) { + return ret; + } + RzListIter *it; + RzRegItem *ri; + CutterRzListForeach (ritems, it, RzRegItem, ri) { RegisterRef reg; - reg.value = value.toUt64(); + reg.value = rz_reg_get_value(core->dbg->reg, ri); reg.ref = getAddrRefs(reg.value, depth); - reg.name = value.key(); + reg.name = ri->name; ret.append(reg); } - + rz_list_free(ritems); return ret; } @@ -1528,9 +1534,8 @@ QList CutterCore::getStack(int size, int depth) } CORE_LOCK(); - bool ret; - RVA addr = cmdRaw("dr SP").toULongLong(&ret, 16); - if (!ret) { + RVA addr = rz_debug_reg_get(core->dbg, "SP"); + if (addr == RVA_INVALID) { return stack; } @@ -1793,11 +1798,6 @@ bool CutterCore::writeHeapChunk(RzHeapChunkSimple *chunk_simple) return rz_heap_write_chunk(core, chunk_simple); } -CutterJson CutterCore::getRegisterValues() -{ - return cmdj("drj"); -} - QList CutterCore::getVariables(RVA at) { QList ret; @@ -1837,42 +1837,52 @@ QList CutterCore::getVariables(RVA at) QVector CutterCore::getRegisterRefValues() { - CutterJson registerRefArray = cmdj("drrj"); QVector result; - - for (CutterJson regRefObject : registerRefArray) { + CORE_LOCK(); + RzList *ritems = rz_core_reg_filter_items_sync(core, core->dbg->reg, reg_sync, nullptr); + if (!ritems) { + return result; + } + RzListIter *it; + RzRegItem *ri; + CutterRzListForeach (ritems, it, RzRegItem, ri) { RegisterRefValueDescription desc; - desc.name = regRefObject[RJsonKey::reg].toString(); - desc.value = regRefObject[RJsonKey::value].toString(); - desc.ref = regRefObject[RJsonKey::ref].toString(); - + desc.name = ri->name; + ut64 value = rz_reg_get_value(core->dbg->reg, ri); + desc.value = QString::number(value); + desc.ref = rz_core_analysis_hasrefs(core, value, true); result.push_back(desc); } + rz_list_free(ritems); return result; } QString CutterCore::getRegisterName(QString registerRole) { - return cmdRaw("drn " + registerRole).trimmed(); + if (!currentlyDebugging) { + return ""; + } + CORE_LOCK(); + return rz_reg_get_name_by_type(core->dbg->reg, registerRole.toUtf8().constData()); } RVA CutterCore::getProgramCounterValue() { - bool ok; if (currentlyDebugging) { - // Use cmd because cmdRaw would not work with inner command backticked - // TODO: Risky command due to changes in API, search for something safer - RVA addr = cmd("dr `drn PC`").toULongLong(&ok, 16); - if (ok) { - return addr; - } + CORE_LOCK(); + return rz_debug_reg_get(core->dbg, "PC"); } return RVA_INVALID; } void CutterCore::setRegister(QString regName, QString regValue) { - cmdRaw(QString("dr %1=%2").arg(regName).arg(regValue)); + if (!currentlyDebugging) { + return; + } + CORE_LOCK(); + ut64 val = rz_num_math(core->num, regValue.toUtf8().constData()); + rz_core_reg_assign_sync(core, core->dbg->reg, reg_sync, regName.toUtf8().constData(), val); emit registersChanged(); emit refreshCodeViews(); } @@ -1940,7 +1950,7 @@ void CutterCore::startDebug() if (!asyncTask( [](RzCore *core) { rz_core_file_reopen_debug(core, ""); - return (void *)NULL; + return (void *)nullptr; }, debugTask)) { return; @@ -1949,9 +1959,7 @@ void CutterCore::startDebug() emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this]() { - if (debugTaskDialog) { - delete debugTaskDialog; - } + delete debugTaskDialog; debugTask.clear(); emit registersChanged(); diff --git a/src/core/Cutter.h b/src/core/Cutter.h index f36796a4..bc76233a 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -417,8 +417,6 @@ public: bool sdbSet(QString path, QString key, QString val); /* Debug */ - CutterJson getRegistersInfo(); - CutterJson getRegisterValues(); QString getRegisterName(QString registerRole); RVA getProgramCounterValue(); void setRegister(QString regName, QString regValue); @@ -444,7 +442,7 @@ public: * @brief return a RefDescription with a formatted ref string and configured colors * @param ref the "ref" JSON node from getAddrRefs */ - RefDescription formatRefDesc(const AddrRefs &ref); + RefDescription formatRefDesc(const QSharedPointer &ref); /** * @brief Get a list of a given process's threads * @param pid The pid of the process, -1 for the currently debugged process diff --git a/src/widgets/RegisterRefsWidget.cpp b/src/widgets/RegisterRefsWidget.cpp index d0cfb4dd..c35e2936 100644 --- a/src/widgets/RegisterRefsWidget.cpp +++ b/src/widgets/RegisterRefsWidget.cpp @@ -190,7 +190,7 @@ void RegisterRefsWidget::refreshRegisterRef() desc.value = RzAddressString(reg.value); desc.reg = reg.name; - desc.refDesc = Core()->formatRefDesc(reg.ref); + desc.refDesc = Core()->formatRefDesc(QSharedPointer::create(reg.ref)); registerRefs.push_back(desc); } diff --git a/src/widgets/StackWidget.cpp b/src/widgets/StackWidget.cpp index d673f8b1..71b66fe4 100644 --- a/src/widgets/StackWidget.cpp +++ b/src/widgets/StackWidget.cpp @@ -154,7 +154,9 @@ void StackModel::reload() item.offset = stackItem.addr; item.value = RzAddressString(stackItem.value); - item.refDesc = Core()->formatRefDesc(*stackItem.ref); + if (!stackItem.ref.isNull()) { + item.refDesc = Core()->formatRefDesc(stackItem.ref); + } values.push_back(item); } From e43a31cc8504632f6cf50906ac2db14c0c8bbef7 Mon Sep 17 00:00:00 2001 From: billow Date: Tue, 17 May 2022 12:01:48 +0800 Subject: [PATCH 111/240] update rizin to cdc80202dd7eaf5bacf0e36a64f964c822e67dd4 --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index a1c2ed18..cdc80202 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit a1c2ed18d762d3641e6690e0cb6b58b45f1c3609 +Subproject commit cdc80202dd7eaf5bacf0e36a64f964c822e67dd4 From c9e8686ecb08b8ec2b4251f0b0ecf98f49e83a29 Mon Sep 17 00:00:00 2001 From: billow Date: Sun, 22 May 2022 16:51:54 +0800 Subject: [PATCH 112/240] Convert Rizin commands to the API calls --- rizin | 2 +- src/common/ColorThemeWorker.cpp | 82 +++-------- src/common/ColorThemeWorker.h | 9 +- src/common/Configuration.cpp | 8 +- src/common/SettingsUpgrade.cpp | 25 ++-- src/core/Cutter.cpp | 134 ++++++++++++------ src/core/Cutter.h | 6 +- .../preferences/ColorThemeEditDialog.cpp | 4 +- src/widgets/BacktraceWidget.cpp | 34 +++-- src/widgets/ColorThemeListView.cpp | 36 ++--- src/widgets/ColorThemeListView.h | 2 +- 11 files changed, 159 insertions(+), 183 deletions(-) diff --git a/rizin b/rizin index cdc80202..f2a1e5e0 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit cdc80202dd7eaf5bacf0e36a64f964c822e67dd4 +Subproject commit f2a1e5e09087550e70122c3a2bedd4e2a02f77f1 diff --git a/src/common/ColorThemeWorker.cpp b/src/common/ColorThemeWorker.cpp index aabc0c1f..c4abfd5c 100644 --- a/src/common/ColorThemeWorker.cpp +++ b/src/common/ColorThemeWorker.cpp @@ -37,9 +37,7 @@ ColorThemeWorker::ColorThemeWorker(QObject *parent) : QObject(parent) QDir().mkpath(customRzThemesLocationPath); } - QDir currDir { - QStringLiteral("%1%2%3").arg(rz_path_prefix(nullptr)).arg(RZ_SYS_DIR).arg(RZ_THEMES) - }; + QDir currDir { QStringLiteral("%1%2%3").arg(rz_path_prefix(nullptr), RZ_SYS_DIR, RZ_THEMES) }; if (currDir.exists()) { standardRzThemesLocationPath = currDir.absolutePath(); } else { @@ -78,27 +76,15 @@ QString ColorThemeWorker::copy(const QString &srcThemeName, const QString ©T return save(getTheme(srcThemeName), copyThemeName); } -QString ColorThemeWorker::save(const QJsonDocument &theme, const QString &themeName) const +QString ColorThemeWorker::save(const Theme &theme, const QString &themeName) const { QFile fOut(QDir(customRzThemesLocationPath).filePath(themeName)); if (!fOut.open(QFile::WriteOnly | QFile::Truncate)) { return tr("The file %1 cannot be opened.").arg(QFileInfo(fOut).filePath()); } - QJsonObject obj = theme.object(); - for (auto it = obj.constBegin(); it != obj.constEnd(); it++) { - - QJsonArray arr = it.value().toArray(); - QColor color; - if (arr.isEmpty()) { - color = it.value().toVariant().value(); - } else if (arr.size() == 4) { - color = QColor(arr[0].toInt(), arr[1].toInt(), arr[2].toInt(), arr[3].toInt()); - } else if (arr.size() == 3) { - color = QColor(arr[0].toInt(), arr[1].toInt(), arr[2].toInt()); - } else { - continue; - } + for (auto it = theme.constBegin(); it != theme.constEnd(); it++) { + const QColor &color = it.value(); if (cutterSpecificOptions.contains(it.key())) { fOut.write(QString("#~%1 rgb:%2\n") .arg(it.key(), color.name(QColor::HexArgb).remove('#')) @@ -125,37 +111,18 @@ bool ColorThemeWorker::isThemeExist(const QString &name) const return themes.contains(name); } -QJsonDocument ColorThemeWorker::getTheme(const QString &themeName) const +ColorThemeWorker::Theme ColorThemeWorker::getTheme(const QString &themeName) const { - int r, g, b, a; - CutterJson rzTheme; - QVariantMap theme; + Theme theme; QString curr = Config()->getColorTheme(); if (themeName != curr) { RzCoreLocked core(Core()); rz_core_theme_load(core, themeName.toUtf8().constData()); - rzTheme = Core()->cmdj("ecj"); + theme = Core()->getTheme(); rz_core_theme_load(core, curr.toUtf8().constData()); } else { - rzTheme = Core()->cmdj("ecj"); - } - - for (CutterJson value : rzTheme) { - QJsonArray arr; - int count = 0; - for (CutterJson element : value) { - arr.append(element.toSt64()); - count++; - if (count >= 3) { - break; - } - } - while (count < 3) { - arr.append(0); - } - arr.append(255); - theme[value.key()] = arr; + theme = Core()->getTheme(); } ColorFlags colorFlags = ColorFlags::DarkFlag; @@ -164,14 +131,13 @@ QJsonDocument ColorThemeWorker::getTheme(const QString &themeName) const } for (auto &it : cutterSpecificOptions) { - Configuration::cutterOptionColors[it][colorFlags].getRgb(&r, &g, &b, &a); - theme.insert(it, QJsonArray { r, g, b, a }); + theme.insert(it, QColor(Configuration::cutterOptionColors[it][colorFlags])); } if (isCustomTheme(themeName)) { QFile src(QDir(customRzThemesLocationPath).filePath(themeName)); if (!src.open(QFile::ReadOnly)) { - return QJsonDocument(); + return {}; } QStringList sl; for (auto &line : QString(src.readAll()).split('\n', CUTTER_QT_SKIP_EMPTY_PARTS)) { @@ -181,8 +147,7 @@ QJsonDocument ColorThemeWorker::getTheme(const QString &themeName) const if (sl.size() != 3 || sl[0][0] == '#') { continue; } - QColor(sl[2]).getRgb(&r, &g, &b, &a); - theme.insert(sl[1], QJsonArray({ r, g, b, a })); + theme.insert(sl[1], QColor(sl[2])); } } @@ -190,21 +155,7 @@ QJsonDocument ColorThemeWorker::getTheme(const QString &themeName) const theme.remove(key); } - // manualy converting instead of using QJsonObject::fromVariantMap because - // Qt < 5.6 QJsonValue.fromVariant doesn't expect QVariant to already contain - // QJson values like QJsonArray. - // https://github.com/qt/qtbase/commit/26237f0a2d8db80024b601f676bbce54d483e672 - QJsonObject obj; - for (auto it = theme.begin(); it != theme.end(); it++) { - auto &value = it.value(); - if (value.canConvert()) { - obj[it.key()] = it.value().value(); - } else { - obj[it.key()] = QJsonValue::fromVariant(value); - } - } - - return QJsonDocument(obj); + return theme; } QString ColorThemeWorker::deleteTheme(const QString &themeName) const @@ -291,11 +242,10 @@ bool ColorThemeWorker::isFileTheme(const QString &filePath, bool *ok) const const QString colors = "black|red|white|green|magenta|yellow|cyan|blue|gray|none"; QString options = - (Core()->cmdj("ecj").keys() << cutterSpecificOptions).join('|').replace(".", "\\."); + (Core()->getThemeKeys() << cutterSpecificOptions).join('|').replace(".", "\\."); - QString pattern = QString("((ec\\s+(%1)\\s+(((rgb:|#)[0-9a-fA-F]{3,8})|(%2))))\\s*") - .arg(options) - .arg(colors); + QString pattern = + QString("((ec\\s+(%1)\\s+(((rgb:|#)[0-9a-fA-F]{3,8})|(%2))))\\s*").arg(options, colors); // The below construct mimics the behaviour of QRegexP::exactMatch(), which was here before QRegularExpression regexp("\\A(?:" + pattern + ")\\z"); @@ -326,7 +276,7 @@ QStringList ColorThemeWorker::customThemes() const const QStringList &ColorThemeWorker::getRizinSpecificOptions() { if (rizinSpecificOptions.isEmpty()) { - rizinSpecificOptions = Core()->cmdj("ecj").keys(); + rizinSpecificOptions << Core()->getThemeKeys(); } return rizinSpecificOptions; } diff --git a/src/common/ColorThemeWorker.h b/src/common/ColorThemeWorker.h index 3d67826f..3942a428 100644 --- a/src/common/ColorThemeWorker.h +++ b/src/common/ColorThemeWorker.h @@ -18,6 +18,8 @@ class ColorThemeWorker : public QObject { Q_OBJECT public: + typedef QHash Theme; + /** * @brief cutterSpecificOptions is list of all available Cutter-only color options. */ @@ -54,7 +56,7 @@ public: * Name of theme to save. * @return "" on success or error message. */ - QString save(const QJsonDocument &theme, const QString &themeName) const; + QString save(const Theme &theme, const QString &themeName) const; /** * @brief Returns whether or not @a themeName theme is custom (created by user or imported) or @@ -71,12 +73,11 @@ public: bool isThemeExist(const QString &name) const; /** - * @brief Returns theme as Json where key is option name and value is array of 3 Ints (Red, - * Green, Blue). + * @brief Returns theme as QHash where key is option name and value is QColor. * @param themeName * Theme to get. */ - QJsonDocument getTheme(const QString &themeName) const; + Theme getTheme(const QString &themeName) const; /** * @brief Deletes theme named @a themeName. diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 0a73eb34..5239ad6b 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -534,13 +534,9 @@ void Configuration::setColorTheme(const QString &theme) s.setValue("theme", theme); } - QJsonObject colorTheme = ThemeWorker().getTheme(theme).object(); + ColorThemeWorker::Theme colorTheme = ThemeWorker().getTheme(theme); for (auto it = colorTheme.constBegin(); it != colorTheme.constEnd(); it++) { - QJsonArray rgb = it.value().toArray(); - if (rgb.size() != 4) { - continue; - } - setColor(it.key(), QColor(rgb[0].toInt(), rgb[1].toInt(), rgb[2].toInt(), rgb[3].toInt())); + setColor(it.key(), it.value()); } emit colorsUpdated(); diff --git a/src/common/SettingsUpgrade.cpp b/src/common/SettingsUpgrade.cpp index 4ef57e59..a03a818a 100644 --- a/src/common/SettingsUpgrade.cpp +++ b/src/common/SettingsUpgrade.cpp @@ -181,26 +181,21 @@ void Cutter::initializeSettings() static void removeObsoleteOptionsFromCustomThemes() { - const QStringList options = Core()->cmdj("ecj").keys() - << ColorThemeWorker::cutterSpecificOptions; - RzList *themes_list = rz_core_theme_list(Core()->core()); - RzListIter *th_iter; - const char *th; - CutterRzListForeach (themes_list, th_iter, const char, th) { - auto theme = QString(th).trimmed(); - if (!ThemeWorker().isCustomTheme(theme)) { + const QStringList options = Core()->getThemeKeys() << ColorThemeWorker::cutterSpecificOptions; + QStringList themes = Core()->getColorThemes(); + for (const auto &themeName : themes) { + if (!ThemeWorker().isCustomTheme(themeName)) { continue; } - QJsonObject updatedTheme; - auto sch = ThemeWorker().getTheme(theme).object(); - for (const auto &key : sch.keys()) { - if (options.contains(key)) { - updatedTheme.insert(key, sch[key]); + ColorThemeWorker::Theme sch = ThemeWorker().getTheme(themeName); + ColorThemeWorker::Theme updatedTheme; + for (auto it = sch.constBegin(); it != sch.constEnd(); ++it) { + if (options.contains(it.key())) { + updatedTheme.insert(it.key(), it.value()); } } - ThemeWorker().save(QJsonDocument(updatedTheme), theme); + ThemeWorker().save(updatedTheme, themeName); } - rz_list_free(themes_list); } void Cutter::migrateThemes() diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 44a79343..3858b88b 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -2157,26 +2157,9 @@ void CutterCore::stopDebug() if (currentlyEmulating) { cmdEsil("aeim-; aei-; wcr; .ar-; aets-"); currentlyEmulating = false; - } else if (currentlyAttachedToPID != -1) { - // Use cmd because cmdRaw would not work with command concatenation - cmd(QString("dp- %1; o %2; .ar-") - .arg(QString::number(currentlyAttachedToPID), currentlyOpenFile)); - currentlyAttachedToPID = -1; } else { - QString ptraceFiles = ""; - // close ptrace file descriptors left open - RzCoreLocked core(Core()); - RzList *descs = rz_id_storage_list(core->io->files); - RzListIter *it; - RzIODesc *desc; - CutterRzListForeach (descs, it, RzIODesc, desc) { - QString URI = QString(desc->uri); - if (URI.contains("ptrace")) { - ptraceFiles += "o-" + QString::number(desc->fd) + ";"; - } - } - // Use cmd because cmdRaw would not work with command concatenation - cmd("doc" + ptraceFiles); + rz_core_debug_process_close(core()); + currentlyAttachedToPID = -1; } syncAndSeekProgramCounter(); @@ -2331,7 +2314,16 @@ void CutterCore::continueUntilSyscall() return; } } else { - if (!asyncCmd("dcs", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_cons_break_push(reinterpret_cast(rz_debug_stop), core->dbg); + rz_reg_arena_swap(core->dbg->reg, true); + rz_debug_continue_syscalls(core->dbg, NULL, 0); + rz_cons_break_pop(); + rz_core_dbg_follow_seek_register(core); + return nullptr; + }, + debugTask)) { return; } } @@ -2390,7 +2382,15 @@ void CutterCore::stepOverDebug() return; } } else { - if (!asyncCmd("dso", debugTask)) { + bool ret; + asyncTask( + [&](RzCore *core) { + ret = rz_core_debug_step_over(core, 1); + rz_core_dbg_follow_seek_register(core); + return nullptr; + }, + debugTask); + if (!ret) { return; } } @@ -2413,7 +2413,15 @@ void CutterCore::stepOutDebug() } emit debugTaskStateChanged(); - if (!asyncCmd("dsf", debugTask)) { + bool ret; + asyncTask( + [&](RzCore *core) { + ret = rz_core_debug_step_until_frame(core); + rz_core_dbg_follow_seek_register(core); + return nullptr; + }, + debugTask); + if (!ret) { return; } @@ -2438,7 +2446,15 @@ void CutterCore::stepBackDebug() return; } } else { - if (!asyncCmd("dsb", debugTask)) { + bool ret; + asyncTask( + [&](RzCore *core) { + ret = rz_core_debug_step_back(core, 1); + rz_core_dbg_follow_seek_register(core); + return nullptr; + }, + debugTask); + if (!ret) { return; } } @@ -2457,11 +2473,11 @@ void CutterCore::stepBackDebug() QStringList CutterCore::getDebugPlugins() { QStringList plugins; - - for (CutterJson pluginObject : cmdj("dLj")) { - QString plugin = pluginObject[RJsonKey::name].toString(); - - plugins << plugin; + RzListIter *iter; + RzDebugPlugin *plugin; + CORE_LOCK(); + CutterRzListForeach (core->dbg->plugins, iter, RzDebugPlugin, plugin) { + plugins << plugin->name; } return plugins; } @@ -2661,11 +2677,9 @@ void CutterCore::disableBreakpoint(RVA addr) void CutterCore::setBreakpointTrace(int index, bool enabled) { - if (enabled) { - cmdRaw(QString("dbite %1").arg(index)); - } else { - cmdRaw(QString("dbitd %1").arg(index)); - } + CORE_LOCK(); + RzBreakpointItem *bpi = rz_bp_get_index(core->dbg->bp, index); + bpi->trace = enabled; } static BreakpointDescription breakpointDescriptionFromRizin(int index, rz_bp_item_t *bpi) @@ -2746,11 +2760,6 @@ bool CutterCore::isBreakpoint(const QList &breakpoints, RVA addr) return breakpoints.contains(addr); } -CutterJson CutterCore::getBacktrace() -{ - return cmdj("dbtj"); -} - QList CutterCore::getProcessThreads(int pid = -1) { CORE_LOCK(); @@ -4120,15 +4129,56 @@ QString CutterCore::getVersionInformation() return versionInfo; } -QList CutterCore::getColorThemes() +QStringList CutterCore::getColorThemes() { - QList r; - for (CutterJson s : cmdj("ecoj")) { - r << s.toString(); + QStringList r; + CORE_LOCK(); + RzList *themes_list = rz_core_theme_list(core); + RzListIter *it; + const char *th; + CutterRzListForeach (themes_list, it, const char, th) { + r << fromOwnedCharPtr(rz_str_trim_dup(th)); } + rz_list_free(themes_list); return r; } +QHash CutterCore::getTheme() +{ + QHash theme; + for (int i = 0;; ++i) { + const char *k = rz_cons_pal_get_name(i); + if (!k) { + break; + } + RzColor color = rz_cons_pal_get_i(i); + theme.insert(k, QColor(color.r, color.g, color.b)); + } + return theme; +} + +QStringList CutterCore::getThemeKeys() +{ + QStringList stringList; + for (int i = 0;; ++i) { + const char *k = rz_cons_pal_get_name(i); + if (!k) { + break; + } + stringList << k; + } + return stringList; +} + +bool CutterCore::setColor(const QString &key, const QString &color) +{ + if (!rz_cons_pal_set(key.toUtf8().constData(), color.toUtf8().constData())) { + return false; + } + rz_cons_pal_update_event(); + return true; +} + QString CutterCore::ansiEscapeToHtml(const QString &text) { int len; diff --git a/src/core/Cutter.h b/src/core/Cutter.h index bc76233a..66b7b0f3 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -393,7 +393,10 @@ public: QString getConfig(const char *k); QString getConfig(const QString &k) { return getConfig(k.toUtf8().constData()); } QString getConfigDescription(const char *k); - QList getColorThemes(); + QStringList getColorThemes(); + QHash getTheme(); + QStringList getThemeKeys(); + bool setColor(const QString &key, const QString &color); /* Assembly\Hexdump related methods */ QByteArray assemble(const QString &code); @@ -449,7 +452,6 @@ public: * @return List of ProcessDescription */ QList getProcessThreads(int pid); - CutterJson getBacktrace(); /** * @brief Get a list of heap chunks * Uses RZ_API rz_heap_chunks_list to get vector of chunks diff --git a/src/dialogs/preferences/ColorThemeEditDialog.cpp b/src/dialogs/preferences/ColorThemeEditDialog.cpp index 93838698..bc0dff62 100644 --- a/src/dialogs/preferences/ColorThemeEditDialog.cpp +++ b/src/dialogs/preferences/ColorThemeEditDialog.cpp @@ -72,7 +72,7 @@ ColorThemeEditDialog::~ColorThemeEditDialog() void ColorThemeEditDialog::accept() { colorTheme = Config()->getColorTheme(); - QJsonDocument sch = ui->colorThemeListView->colorSettingsModel()->getTheme(); + ColorThemeWorker::Theme sch = ui->colorThemeListView->colorSettingsModel()->getTheme(); if (ThemeWorker().isCustomTheme(colorTheme)) { QString err = ThemeWorker().save(sch, colorTheme); if (!err.isEmpty()) { @@ -133,7 +133,7 @@ void ColorThemeEditDialog::colorOptionChanged(const QColor &newColor) Config()->setColor(currOption.optionName, currOption.color); if (!ColorThemeWorker::cutterSpecificOptions.contains(currOption.optionName)) { - Core()->cmdRaw(QString("ec %1 %2").arg(currOption.optionName).arg(currOption.color.name())); + Core()->setColor(currOption.optionName, currOption.color.name()); } previewDisasmWidget->colorsUpdatedSlot(); } diff --git a/src/widgets/BacktraceWidget.cpp b/src/widgets/BacktraceWidget.cpp index 433a1b1e..d4413c39 100644 --- a/src/widgets/BacktraceWidget.cpp +++ b/src/widgets/BacktraceWidget.cpp @@ -44,27 +44,25 @@ void BacktraceWidget::updateContents() void BacktraceWidget::setBacktraceGrid() { + RzList *list = rz_core_debug_backtraces(Core()->core()); int i = 0; - for (CutterJson backtraceItem : Core()->getBacktrace()) { - QString progCounter = RzAddressString(backtraceItem["pc"].toRVA()); - QString stackPointer = RzAddressString(backtraceItem["sp"].toRVA()); - st64 frameSize = backtraceItem["frame_size"].toSt64(); - QString funcName = backtraceItem["fname"].toString(); - QString desc = backtraceItem["desc"].toString(); + RzListIter *iter; + RzBacktrace *bt; + CutterRzListForeach (list, iter, RzBacktrace, bt) { + QString funcName = bt->fcn ? bt->fcn->name : ""; + QString pc = RzAddressString(bt->frame ? bt->frame->addr : 0); + QString sp = RzAddressString(bt->frame ? bt->frame->sp : 0); + QString frameSize = QString::number(bt->frame ? bt->frame->size : 0); + QString desc = bt->desc; - QStandardItem *rowPC = new QStandardItem(progCounter); - QStandardItem *rowSP = new QStandardItem(stackPointer); - QStandardItem *rowFrameSize = new QStandardItem(QString::number(frameSize)); - QStandardItem *rowFuncName = new QStandardItem(funcName); - QStandardItem *rowDesc = new QStandardItem(desc); - - modelBacktrace->setItem(i, 0, rowFuncName); - modelBacktrace->setItem(i, 1, rowSP); - modelBacktrace->setItem(i, 2, rowPC); - modelBacktrace->setItem(i, 3, rowDesc); - modelBacktrace->setItem(i, 4, rowFrameSize); - i++; + modelBacktrace->setItem(i, 0, new QStandardItem(funcName)); + modelBacktrace->setItem(i, 1, new QStandardItem(sp)); + modelBacktrace->setItem(i, 2, new QStandardItem(pc)); + modelBacktrace->setItem(i, 3, new QStandardItem(desc)); + modelBacktrace->setItem(i, 4, new QStandardItem(frameSize)); + ++i; } + rz_list_free(list); // Remove irrelevant old rows if (modelBacktrace->rowCount() > i) { diff --git a/src/widgets/ColorThemeListView.cpp b/src/widgets/ColorThemeListView.cpp index a5c93354..7d534f57 100644 --- a/src/widgets/ColorThemeListView.cpp +++ b/src/widgets/ColorThemeListView.cpp @@ -220,13 +220,7 @@ ColorThemeListView::ColorThemeListView(QWidget *parent) : QListView(parent) setItemDelegate(new ColorOptionDelegate(this)); setResizeMode(ResizeMode::Adjust); - QJsonArray rgb = - colorSettingsModel()->getTheme().object().find("gui.background").value().toArray(); - if (rgb.size() == 3) { - backgroundColor = QColor(rgb[0].toInt(), rgb[1].toInt(), rgb[2].toInt()); - } else { - backgroundColor = palette().base().color(); - } + backgroundColor = colorSettingsModel()->getTheme().find("gui.background").value(); connect(&blinkTimer, &QTimer::timeout, this, &ColorThemeListView::blinkTimeout); @@ -241,7 +235,7 @@ void ColorThemeListView::currentChanged(const QModelIndex ¤t, const QModel ColorOption prev = previous.data(Qt::UserRole).value(); Config()->setColor(prev.optionName, prev.color); if (ThemeWorker().getRizinSpecificOptions().contains(prev.optionName)) { - Core()->cmdRaw(QString("ec %1 %2").arg(prev.optionName).arg(prev.color.name())); + Core()->setColor(prev.optionName, prev.color.name()); } QListView::currentChanged(current, previous); @@ -267,9 +261,7 @@ void ColorThemeListView::mouseReleaseEvent(QMouseEvent *e) .contains(e->pos())) { ColorOption co = currentIndex().data(Qt::UserRole).value(); co.changed = false; - QJsonArray rgb = - ThemeWorker().getTheme(Config()->getColorTheme()).object()[co.optionName].toArray(); - co.color = QColor(rgb[0].toInt(), rgb[1].toInt(), rgb[2].toInt()); + co.color = ThemeWorker().getTheme(Config()->getColorTheme())[co.optionName]; model()->setData(currentIndex(), QVariant::fromValue(co)); QCursor c; c.setShape(Qt::CursorShape::ArrowCursor); @@ -307,7 +299,7 @@ void ColorThemeListView::blinkTimeout() auto updateColor = [](const QString &name, const QColor &color) { Config()->setColor(name, color); if (ThemeWorker().getRizinSpecificOptions().contains(name)) { - Core()->cmdRaw(QString("ec %1 %2").arg(name).arg(color.name())); + Core()->setColor(name, color.name()); } }; @@ -374,16 +366,10 @@ void ColorSettingsModel::updateTheme() { beginResetModel(); theme.clear(); - QJsonObject obj = ThemeWorker().getTheme(Config()->getColorTheme()).object(); + ColorThemeWorker::Theme obj = ThemeWorker().getTheme(Config()->getColorTheme()); for (auto it = obj.constBegin(); it != obj.constEnd(); it++) { - QJsonArray rgb = it.value().toArray(); - if (rgb.size() != 4) { - continue; - } - theme.push_back({ it.key(), - QColor(rgb[0].toInt(), rgb[1].toInt(), rgb[2].toInt(), rgb[3].toInt()), - false }); + theme.push_back({ it.key(), it.value(), false }); } std::sort(theme.begin(), theme.end(), [](const ColorOption &f, const ColorOption &s) { @@ -395,15 +381,13 @@ void ColorSettingsModel::updateTheme() endResetModel(); } -QJsonDocument ColorSettingsModel::getTheme() const +ColorThemeWorker::Theme ColorSettingsModel::getTheme() const { - QJsonObject obj; - int r, g, b, a; + ColorThemeWorker::Theme th; for (auto &it : theme) { - it.color.getRgb(&r, &g, &b, &a); - obj.insert(it.optionName, QJsonArray({ r, g, b, a })); + th.insert(it.optionName, it.color); } - return QJsonDocument(obj); + return th; } const QMap optionInfoMap__ = { diff --git a/src/widgets/ColorThemeListView.h b/src/widgets/ColorThemeListView.h index 8525312d..f992f2f7 100644 --- a/src/widgets/ColorThemeListView.h +++ b/src/widgets/ColorThemeListView.h @@ -73,7 +73,7 @@ public: void updateTheme(); - QJsonDocument getTheme() const; + QHash getTheme() const; private: QList theme; From 147af535655a6f60c89dce5815a3cd781428b699 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Tue, 24 May 2022 20:47:59 +0200 Subject: [PATCH 113/240] Fix the lib name on windows (#2950) --- cmake/BundledRizin.cmake | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index 4dcf4301..83e4c128 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -46,6 +46,10 @@ else() link_directories("${RIZIN_INSTALL_DIR}/lib") endif() +# TODO: This version number should be fetched automatically +# instead of being hardcoded. +set (Rizin_VERSION 0.4) + set (RZ_LIBS rz_core rz_config rz_cons rz_io rz_util rz_flag rz_asm rz_debug rz_hash rz_bin rz_lang rz_il rz_analysis rz_parse rz_bp rz_egg rz_reg rz_search rz_syscall rz_socket rz_magic rz_crypto rz_type rz_diff rz_sign @@ -62,11 +66,11 @@ target_include_directories(Rizin INTERFACE install(TARGETS Rizin EXPORT CutterTargets) if (WIN32) - foreach(_lib ${RZ_LIBS} ${RZ_EXTRA_LIBS}) - install(FILES "${RIZIN_INSTALL_DIR}/${RZ_INSTALL_BINPATH}/${_lib}.dll" DESTINATION "${CMAKE_INSTALL_BINDIR}") + foreach(_lib ${RZ_LIBS} ${RZ_EXTRA_LIBS}) + install(FILES "${RIZIN_INSTALL_DIR}/${_lib}-${Rizin_VERSION}.dll" DESTINATION "${CMAKE_INSTALL_BINDIR}") endforeach() foreach(_exe ${RZ_BIN}) - install(FILES "${RIZIN_INSTALL_DIR}/${RZ_INSTALL_BINPATH}/${_exe}.exe" DESTINATION "${CMAKE_INSTALL_BINDIR}") + install(FILES "${RIZIN_INSTALL_DIR}/${_exe}.exe" DESTINATION "${CMAKE_INSTALL_BINDIR}") endforeach() install(DIRECTORY "${RIZIN_INSTALL_DIR}/share" DESTINATION ".") install(DIRECTORY "${RIZIN_INSTALL_DIR}/include" DESTINATION "." From 150769cd6b383da6061c7406cdc983daa24cab85 Mon Sep 17 00:00:00 2001 From: billow Date: Sat, 28 May 2022 16:09:00 +0800 Subject: [PATCH 114/240] Convert Rizin commands to the API calls (#2948) Including wx wr wd ws ww wz ahi ahb aec aecu aecc aecs aes aesb aets+ aets- afc afcl omfg+w oo+ oo p8 aei aeim aeip aecb aeso dbs avj --- rizin | 2 +- src/core/Cutter.cpp | 194 ++++++++++++++++++--------- src/dialogs/WriteCommandsDialogs.cpp | 10 +- src/menus/DisassemblyContextMenu.cpp | 24 +++- src/widgets/HexWidget.cpp | 156 ++++++++++++--------- 5 files changed, 247 insertions(+), 139 deletions(-) diff --git a/rizin b/rizin index f2a1e5e0..24524f26 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit f2a1e5e09087550e70122c3a2bedd4e2a02f77f1 +Subproject commit 24524f26b5e4db58a736f702a77e79245148c559 diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 3858b88b..40cd43ff 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -656,7 +656,10 @@ bool CutterCore::loadFile(QString path, ut64 baddr, ut64 mapaddr, int perms, int } if (perms & RZ_PERM_W) { - rz_core_cmd0(core, "omfg+w"); + RzPVector *maps = rz_io_maps(core->io); + for (auto map : CutterPVector(maps)) { + map->perm |= RZ_PERM_W; + } } fflush(stdout); @@ -802,7 +805,8 @@ void CutterCore::jmpReverse(RVA addr) void CutterCore::editBytes(RVA addr, const QString &bytes) { - cmdRawAt(QString("wx %1").arg(bytes), addr); + CORE_LOCK(); + rz_core_write_hexpair(core, addr, bytes.toUtf8().constData()); emit instructionChanged(addr); } @@ -935,8 +939,9 @@ void CutterCore::setImmediateBase(const QString &rzBaseName, RVA offset) if (offset == RVA_INVALID) { offset = getOffset(); } - - this->cmdRawAt(QString("ahi %1").arg(rzBaseName), offset); + CORE_LOCK(); + int base = (int)rz_num_base_of_string(core->num, rzBaseName.toUtf8().constData()); + rz_analysis_hint_set_immbase(core->analysis, offset, base); emit instructionChanged(offset); } @@ -946,7 +951,8 @@ void CutterCore::setCurrentBits(int bits, RVA offset) offset = getOffset(); } - this->cmdRawAt(QString("ahb %1").arg(bits), offset); + CORE_LOCK(); + rz_analysis_hint_set_bits(core->analysis, offset, bits); emit instructionChanged(offset); } @@ -1950,7 +1956,7 @@ void CutterCore::startDebug() if (!asyncTask( [](RzCore *core) { rz_core_file_reopen_debug(core, ""); - return (void *)nullptr; + return nullptr; }, debugTask)) { return; @@ -1991,14 +1997,19 @@ void CutterCore::startEmulation() } // clear registers, init esil state, stack, progcounter at current seek - asyncCmd("aei; aeim; aeip", debugTask); + asyncTask( + [&](RzCore *core) { + rz_core_analysis_esil_reinit(core); + rz_core_analysis_esil_init_mem(core, NULL, UT64_MAX, UT32_MAX); + rz_core_analysis_esil_init_regs(core); + return nullptr; + }, + debugTask); emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this]() { - if (debugTaskDialog) { - delete debugTaskDialog; - } + delete debugTaskDialog; debugTask.clear(); if (!currentlyDebugging || !currentlyEmulating) { @@ -2105,9 +2116,7 @@ void CutterCore::attachDebug(int pid) emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this, pid]() { - if (debugTaskDialog) { - delete debugTaskDialog; - } + delete debugTaskDialog; debugTask.clear(); syncAndSeekProgramCounter(); @@ -2184,14 +2193,20 @@ void CutterCore::continueDebug() } if (currentlyEmulating) { - if (!asyncCmdEsil("aec", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_esil_step(core, UT64_MAX, "0", NULL, false); + rz_core_reg_update_flags(core); + return nullptr; + }, + debugTask)) { return; } } else { if (!asyncTask( [](RzCore *core) { rz_debug_continue(core->dbg); - return (void *)NULL; + return nullptr; }, debugTask)) { return; @@ -2216,14 +2231,20 @@ void CutterCore::continueBackDebug() } if (currentlyEmulating) { - if (!asyncCmdEsil("aecb", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_esil_continue_back(core); + rz_core_reg_update_flags(core); + return nullptr; + }, + debugTask)) { return; } } else { if (!asyncTask( [](RzCore *core) { rz_debug_continue_back(core->dbg); - return (void *)NULL; + return nullptr; }, debugTask)) { return; @@ -2248,14 +2269,20 @@ void CutterCore::continueUntilDebug(ut64 offset) } if (currentlyEmulating) { - if (!asyncCmdEsil("aecu " + QString::number(offset), debugTask)) { + if (!asyncTask( + [=](RzCore *core) { + rz_core_esil_step(core, offset, NULL, NULL, false); + rz_core_reg_update_flags(core); + return nullptr; + }, + debugTask)) { return; } } else { if (!asyncTask( [=](RzCore *core) { rz_core_debug_continue_until(core, offset, offset); - return (void *)NULL; + return nullptr; }, debugTask)) { return; @@ -2278,14 +2305,19 @@ void CutterCore::continueUntilCall() } if (currentlyEmulating) { - if (!asyncCmdEsil("aecc", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_analysis_continue_until_call(core); + return nullptr; + }, + debugTask)) { return; } } else { if (!asyncTask( [](RzCore *core) { rz_core_debug_step_one(core, 0); - return (void *)NULL; + return nullptr; }, debugTask)) { return; @@ -2310,7 +2342,12 @@ void CutterCore::continueUntilSyscall() } if (currentlyEmulating) { - if (!asyncCmdEsil("aecs", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_analysis_continue_until_syscall(core); + return nullptr; + }, + debugTask)) { return; } } else { @@ -2346,14 +2383,20 @@ void CutterCore::stepDebug() } if (currentlyEmulating) { - if (!asyncCmdEsil("aes", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_esil_step(core, UT64_MAX, NULL, NULL, false); + rz_core_reg_update_flags(core); + return nullptr; + }, + debugTask)) { return; } } else { if (!asyncTask( [](RzCore *core) { rz_core_debug_step_one(core, 1); - return (void *)NULL; + return nullptr; }, debugTask)) { return; @@ -2378,7 +2421,12 @@ void CutterCore::stepOverDebug() } if (currentlyEmulating) { - if (!asyncCmdEsil("aeso", debugTask)) { + if (!asyncTask( + [&](RzCore *core) { + rz_core_analysis_esil_step_over(core); + return nullptr; + }, + debugTask)) { return; } } else { @@ -2442,7 +2490,13 @@ void CutterCore::stepBackDebug() } if (currentlyEmulating) { - if (!asyncCmdEsil("aesb", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_esil_step_back(core); + rz_core_reg_update_flags(core); + return nullptr; + }, + debugTask)) { return; } } else { @@ -2499,7 +2553,12 @@ void CutterCore::startTraceSession() } if (currentlyEmulating) { - if (!asyncCmdEsil("aets+", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_analysis_esil_trace_start(core); + return nullptr; + }, + debugTask)) { return; } } else { @@ -2507,7 +2566,7 @@ void CutterCore::startTraceSession() [](RzCore *core) { core->dbg->session = rz_debug_session_new(); rz_debug_add_checkpoint(core->dbg); - return (void *)NULL; + return nullptr; }, debugTask)) { return; @@ -2516,9 +2575,7 @@ void CutterCore::startTraceSession() emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this]() { - if (debugTaskDialog) { - delete debugTaskDialog; - } + delete debugTaskDialog; debugTask.clear(); currentlyTracing = true; @@ -2541,7 +2598,12 @@ void CutterCore::stopTraceSession() } if (currentlyEmulating) { - if (!asyncCmdEsil("aets-", debugTask)) { + if (!asyncTask( + [](RzCore *core) { + rz_core_analysis_esil_trace_stop(core); + return nullptr; + }, + debugTask)) { return; } } else { @@ -2549,7 +2611,7 @@ void CutterCore::stopTraceSession() [](RzCore *core) { rz_debug_session_free(core->dbg->session); core->dbg->session = NULL; - return (void *)NULL; + return nullptr; }, debugTask)) { return; @@ -2558,9 +2620,7 @@ void CutterCore::stopTraceSession() emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this]() { - if (debugTaskDialog) { - delete debugTaskDialog; - } + delete debugTaskDialog; debugTask.clear(); currentlyTracing = false; @@ -2578,7 +2638,8 @@ void CutterCore::stopTraceSession() void CutterCore::toggleBreakpoint(RVA addr) { - cmdRaw(QString("dbs %1").arg(addr)); + CORE_LOCK(); + rz_core_debug_breakpoint_toggle(core, addr); emit breakpointsChanged(addr); } @@ -3649,25 +3710,29 @@ QList CutterCore::getAllResources() QList CutterCore::getAllVTables() { CORE_LOCK(); - QList vtables; - - for (CutterJson vTableObject : cmdj("avj")) { - VTableDescription res; - - res.addr = vTableObject[RJsonKey::offset].toRVA(); - - for (CutterJson methodObject : vTableObject[RJsonKey::methods]) { - BinClassMethodDescription method; - - method.addr = methodObject[RJsonKey::offset].toRVA(); - method.name = methodObject[RJsonKey::name].toString(); - - res.methods << method; + QList vtableDescs; + RVTableContext context; + rz_analysis_vtable_begin(core->analysis, &context); + RzList *vtables = rz_analysis_vtable_search(&context); + RzListIter *iter; + RVTableInfo *table; + RVTableMethodInfo *method; + CutterRzListForeach (vtables, iter, RVTableInfo, table) { + VTableDescription tableDesc; + tableDesc.addr = table->saddr; + CutterRzVectorForeach(&table->methods, method, RVTableMethodInfo) + { + BinClassMethodDescription methodDesc; + RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, method->addr, 0); + const char *fname = fcn ? fcn->name : nullptr; + methodDesc.addr = method->addr; + methodDesc.name = fname ? fname : "No Name found"; + tableDesc.methods << methodDesc; } - - vtables << res; + vtableDescs << tableDesc; } - return vtables; + rz_list_free(vtables); + return vtableDescs; } QList CutterCore::getAllTypes() @@ -4226,10 +4291,10 @@ void CutterCore::commitWriteCache() TempConfig tempConfig; tempConfig.set("io.cache", false); if (!isWriteModeEnabled()) { - cmdRaw("oo+"); + rz_core_io_file_reopen(core, core->io->desc->fd, RZ_PERM_RW); rz_io_cache_commit(core->io, 0, UT64_MAX); rz_core_block_read(core); - cmdRaw("oo"); + rz_core_io_file_open(core, core->io->desc->fd); } else { rz_io_cache_commit(core->io, 0, UT64_MAX); rz_core_block_read(core); @@ -4252,17 +4317,22 @@ void CutterCore::setWriteMode(bool enabled) return; } + CORE_LOCK(); // Change from read-only to write-mode - if (enabled && !writeModeState) { - cmdRaw("oo+"); - // Change from write-mode to read-only + if (enabled) { + if (!writeModeState) { + rz_core_io_file_reopen(core, core->io->desc->fd, RZ_PERM_RW); + } } else { - cmdRaw("oo"); + // Change from write-mode to read-only + rz_core_io_file_open(core, core->io->desc->fd); } // Disable cache mode because we specifically set write or // read-only modes. - setIOCache(false); - writeModeChanged(enabled); + if (this->iocache) { + setIOCache(false); + } + emit writeModeChanged(enabled); emit ioModeChanged(); } diff --git a/src/dialogs/WriteCommandsDialogs.cpp b/src/dialogs/WriteCommandsDialogs.cpp index 5826a9ae..9cd509a3 100644 --- a/src/dialogs/WriteCommandsDialogs.cpp +++ b/src/dialogs/WriteCommandsDialogs.cpp @@ -77,14 +77,12 @@ size_t DuplicateFromOffsetDialog::getNBytes() const void DuplicateFromOffsetDialog::refresh() { - RVA offestFrom = getOffset(); - QSignalBlocker sb(Core()); + RzCoreLocked core(Core()); + auto buf = Core()->ioRead(getOffset(), (int)getNBytes()); // Add space every two characters for word wrap in hex sequence QRegularExpression re { "(.{2})" }; - QString bytes = Core()->cmdRawAt(QString("p8 %1").arg(QString::number(getNBytes())), offestFrom) - .replace(re, "\\1 "); - - ui->bytesLabel->setText(bytes.trimmed()); + auto bytes = QString(buf).replace(re, "\\1 ").trimmed(); + ui->bytesLabel->setText(bytes); } diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 2f6c6d66..a60e2196 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -1014,8 +1014,18 @@ void DisassemblyContextMenu::on_actionEditFunction_triggered() dialog.setStackSizeText(QString::number(fcn->stack)); - QStringList callConList = Core()->cmdRaw("afcl").split("\n"); - callConList.removeLast(); + QStringList callConList; + RzList *list = rz_analysis_calling_conventions(core->analysis); + if (!list) { + return; + } + RzListIter *iter; + const char *cc; + CutterRzListForeach (list, iter, const char, cc) { + callConList << cc; + } + rz_list_free(list); + dialog.setCallConList(callConList); dialog.setCallConSelected(fcn->cc); @@ -1026,7 +1036,15 @@ void DisassemblyContextMenu::on_actionEditFunction_triggered() fcn->addr = Core()->math(new_start_addr); QString new_stack_size = dialog.getStackSizeText(); fcn->stack = int(Core()->math(new_stack_size)); - Core()->cmdRaw("afc " + dialog.getCallConSelected()); + + const char *ccSelected = dialog.getCallConSelected().toUtf8().constData(); + if (RZ_STR_ISEMPTY(ccSelected)) { + return; + } + if (rz_analysis_cc_exist(core->analysis, ccSelected)) { + fcn->cc = rz_str_constpool_get(&core->analysis->constpool, ccSelected); + } + emit Core()->functionsChanged(); } } diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index b02a0e12..76cc586a 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -131,7 +131,8 @@ HexWidget::HexWidget(QWidget *parent) // delete comment option actionDeleteComment = new QAction(tr("Delete Comment"), this); actionDeleteComment->setShortcutContext(Qt::ShortcutContext::WidgetWithChildrenShortcut); - connect(actionDeleteComment, &QAction::triggered, this, &HexWidget::on_actionDeleteComment_triggered); + connect(actionDeleteComment, &QAction::triggered, this, + &HexWidget::on_actionDeleteComment_triggered); addAction(actionDeleteComment); actionSelectRange = new QAction(tr("Select range"), this); @@ -713,14 +714,14 @@ void HexWidget::copyAddress() clipboard->setText(RzAddressString(addr)); } -//slot for add comment action +// slot for add comment action void HexWidget::on_actionAddComment_triggered() { uint64_t addr = cursor.address; CommentsDialog::addOrEditComment(addr, this); } -//slot for deleting comment action +// slot for deleting comment action void HexWidget::on_actionDeleteComment_triggered() { uint64_t addr = cursor.address; @@ -742,14 +743,16 @@ void HexWidget::w_writeString() return; } bool ok = false; - QInputDialog d; - d.setInputMode(QInputDialog::InputMode::TextInput); - QString str = d.getText(this, tr("Write string"), tr("String:"), QLineEdit::Normal, "", &ok); - if (ok && !str.isEmpty()) { + QString str = QInputDialog::getText(this, tr("Write string"), tr("String:"), QLineEdit::Normal, + "", &ok); + if (!ok || str.isEmpty()) { + return; + } + { RzCoreLocked core(Core()); rz_core_write_string_at(core, getLocationAddress(), str.toUtf8().constData()); - refresh(); } + refresh(); } void HexWidget::w_increaseDecrease() @@ -767,8 +770,10 @@ void HexWidget::w_increaseDecrease() if (d.getMode() == IncrementDecrementDialog::Decrease) { value *= -1; } - RzCoreLocked core(Core()); - rz_core_write_value_inc_at(core, getLocationAddress(), value, sz); + { + RzCoreLocked core(Core()); + rz_core_write_value_inc_at(core, getLocationAddress(), value, sz); + } refresh(); } @@ -784,10 +789,8 @@ void HexWidget::w_writeBytes() size = static_cast(selection.size()); } - QInputDialog d; - d.setInputMode(QInputDialog::InputMode::TextInput); - QByteArray bytes = d.getText(this, tr("Write hex bytes"), tr("Hex byte string:"), - QLineEdit::Normal, "", &ok) + QByteArray bytes = QInputDialog::getText(this, tr("Write hex bytes"), tr("Hex byte string:"), + QLineEdit::Normal, "", &ok) .toUtf8(); const int offset = bytes.startsWith("\\x") ? 2 : 0; const int incr = offset + 2; @@ -795,16 +798,18 @@ void HexWidget::w_writeBytes() if (!ok || !bytes_size) { return; } - uint8_t *buf = (uint8_t *)malloc(static_cast(bytes_size)); - if (!buf) { - return; + { + auto *buf = (uint8_t *)malloc(static_cast(bytes_size)); + if (!buf) { + return; + } + for (int i = 0, j = 0, sz = bytes.size(); i < sz; i += incr, j++) { + buf[j] = static_cast(bytes.mid(i + offset, 2).toInt(nullptr, 16)); + } + RzCoreLocked core(Core()); + rz_core_write_at(core, getLocationAddress(), buf, bytes_size); + free(buf); } - for (int i = 0, j = 0, sz = bytes.size(); i < sz; i += incr, j++) { - buf[j] = static_cast(bytes.mid(i + offset, 2).toInt(nullptr, 16)); - } - RzCoreLocked core(Core()); - rz_core_write_at(core, getLocationAddress(), buf, bytes_size); - free(buf); refresh(); } @@ -813,24 +818,25 @@ void HexWidget::w_writeZeros() if (!ioModesController.prepareForWriting()) { return; } - bool ok = false; - QInputDialog d; int size = 1; if (!selection.isEmpty() && selection.size() <= INT_MAX) { size = static_cast(selection.size()); } - int len = - d.getInt(this, tr("Write zeros"), tr("Number of zeros:"), size, 1, 0x7FFFFFFF, 1, &ok); - if (ok) { + bool ok = false; + int len = QInputDialog::getInt(this, tr("Write zeros"), tr("Number of zeros:"), size, 1, + 0x7FFFFFFF, 1, &ok); + if (!ok) { + return; + } + { RzCoreLocked core(Core()); - uint8_t *buf = (uint8_t *)calloc(len, sizeof(uint8_t)); + auto *buf = (uint8_t *)calloc(len, sizeof(uint8_t)); rz_core_write_at(core, getLocationAddress(), buf, len); free(buf); - - refresh(); } + refresh(); } void HexWidget::w_write64() @@ -855,11 +861,13 @@ void HexWidget::w_write64() return; } - RzCoreLocked core(Core()); - if (d.getMode() == Base64EnDecodedWriteDialog::Encode) { - rz_core_write_base64_at(core, getLocationAddress(), str.toHex().constData()); - } else { - rz_core_write_base64d_at(core, getLocationAddress(), str.constData()); + { + RzCoreLocked core(Core()); + if (d.getMode() == Base64EnDecodedWriteDialog::Encode) { + rz_core_write_base64_at(core, getLocationAddress(), str.toHex().constData()); + } else { + rz_core_write_base64d_at(core, getLocationAddress(), str.constData()); + } } refresh(); } @@ -869,19 +877,24 @@ void HexWidget::w_writeRandom() if (!ioModesController.prepareForWriting()) { return; } - bool ok = false; - QInputDialog d; int size = 1; if (!selection.isEmpty() && selection.size() <= INT_MAX) { size = static_cast(selection.size()); } - QString nbytes = QString::number(d.getInt(this, tr("Write random"), tr("Number of bytes:"), - size, 1, 0x7FFFFFFF, 1, &ok)); - if (ok && !nbytes.isEmpty()) { - Core()->cmdRawAt(QString("wr %1").arg(nbytes), getLocationAddress()); - refresh(); + + bool ok = false; + int nbytes = QInputDialog::getInt(this, tr("Write random"), tr("Number of bytes:"), size, 1, + 0x7FFFFFFF, 1, &ok); + if (!ok) { + return; } + + { + RzCoreLocked core(Core()); + rz_core_write_random_at(core, getLocationAddress(), nbytes); + } + refresh(); } void HexWidget::w_duplFromOffset() @@ -894,9 +907,12 @@ void HexWidget::w_duplFromOffset() if (ret == QDialog::Rejected) { return; } - RVA copyFrom = d.getOffset(); - QString nBytes = QString::number(d.getNBytes()); - Core()->cmdRawAt(QString("wd %1 %2").arg(copyFrom).arg(nBytes), getLocationAddress()); + RVA src = d.getOffset(); + int len = (int)d.getNBytes(); + { + RzCoreLocked core(Core()); + rz_core_write_duplicate_at(core, getLocationAddress(), src, len); + } refresh(); } @@ -906,14 +922,16 @@ void HexWidget::w_writePascalString() return; } bool ok = false; - QInputDialog d; - d.setInputMode(QInputDialog::InputMode::TextInput); - QString str = - d.getText(this, tr("Write Pascal string"), tr("String:"), QLineEdit::Normal, "", &ok); - if (ok && !str.isEmpty()) { - Core()->cmdRawAt(QString("ws %1").arg(str), getLocationAddress()); - refresh(); + QString str = QInputDialog::getText(this, tr("Write Pascal string"), tr("String:"), + QLineEdit::Normal, "", &ok); + if (!ok || str.isEmpty()) { + return; } + { + RzCoreLocked core(Core()); + rz_core_write_length_string_at(core, getLocationAddress(), str.toUtf8().constData()); + } + refresh(); } void HexWidget::w_writeWideString() @@ -922,14 +940,16 @@ void HexWidget::w_writeWideString() return; } bool ok = false; - QInputDialog d; - d.setInputMode(QInputDialog::InputMode::TextInput); - QString str = - d.getText(this, tr("Write wide string"), tr("String:"), QLineEdit::Normal, "", &ok); - if (ok && !str.isEmpty()) { - Core()->cmdRawAt(QString("ww %1").arg(str), getLocationAddress()); - refresh(); + QString str = QInputDialog::getText(this, tr("Write wide string"), tr("String:"), + QLineEdit::Normal, "", &ok); + if (!ok || str.isEmpty()) { + return; } + { + RzCoreLocked core(Core()); + rz_core_write_string_wide_at(core, getLocationAddress(), str.toUtf8().constData()); + } + refresh(); } void HexWidget::w_writeCString() @@ -938,14 +958,16 @@ void HexWidget::w_writeCString() return; } bool ok = false; - QInputDialog d; - d.setInputMode(QInputDialog::InputMode::TextInput); - QString str = d.getText(this, tr("Write zero-terminated string"), tr("String:"), - QLineEdit::Normal, "", &ok); - if (ok && !str.isEmpty()) { - Core()->cmdRawAt(QString("wz %1").arg(str), getLocationAddress()); - refresh(); + QString str = QInputDialog::getText(this, tr("Write zero-terminated string"), tr("String:"), + QLineEdit::Normal, "", &ok); + if (!ok || str.isEmpty()) { + return; } + { + RzCoreLocked core(Core()); + rz_core_write_string_zero_at(core, getLocationAddress(), str.toUtf8().constData()); + } + refresh(); } void HexWidget::updateItemLength() From 1914b34fd8569b852d1981dc27184922c7b43248 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 30 May 2022 13:01:55 +0200 Subject: [PATCH 115/240] Refactor VisualNavbar to use API instead of p-j (#2953) With the updated rizin, this also fixes any error prints saying "Cannot alloc for this range" and json errors when no valid range is available. --- rizin | 2 +- src/core/Cutter.cpp | 54 ---------------------------- src/core/Cutter.h | 1 - src/widgets/VisualNavbar.cpp | 69 ++++++++++++++++++++++++++---------- src/widgets/VisualNavbar.h | 6 +++- 5 files changed, 57 insertions(+), 75 deletions(-) diff --git a/rizin b/rizin index 24524f26..0950e823 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 24524f26b5e4db58a736f702a77e79245148c559 +Subproject commit 0950e823a4502677cbf77cfd0266e8de64875fc0 diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 40cd43ff..ee27caaa 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3857,60 +3857,6 @@ QList CutterCore::getAllSearch(QString searchFor, QString spa return searchRef; } -BlockStatistics CutterCore::getBlockStatistics(unsigned int blocksCount) -{ - BlockStatistics blockStats; - if (blocksCount == 0) { - blockStats.from = blockStats.to = blockStats.blocksize = 0; - return blockStats; - } - - CutterJson statsObj; - - // User TempConfig here to set the search boundaries to all sections. This makes sure - // that the Visual Navbar will show all the relevant addresses. - { - TempConfig tempConfig; - tempConfig.set("search.in", "bin.sections"); - statsObj = cmdj("p-j " + QString::number(blocksCount)); - } - - blockStats.from = statsObj[RJsonKey::from].toRVA(); - blockStats.to = statsObj[RJsonKey::to].toRVA(); - blockStats.blocksize = statsObj[RJsonKey::blocksize].toRVA(); - - for (CutterJson blockObj : statsObj[RJsonKey::blocks]) { - BlockDescription block; - - block.addr = blockObj[RJsonKey::offset].toRVA(); - block.size = blockObj[RJsonKey::size].toRVA(); - block.flags = blockObj[RJsonKey::flags].toSt64(); - block.functions = blockObj[RJsonKey::functions].toSt64(); - block.inFunctions = blockObj[RJsonKey::in_functions].toSt64(); - block.comments = blockObj[RJsonKey::comments].toSt64(); - block.symbols = blockObj[RJsonKey::symbols].toSt64(); - block.strings = blockObj[RJsonKey::strings].toSt64(); - - block.rwx = 0; - QString rwxStr = blockObj[RJsonKey::rwx].toString(); - if (rwxStr.length() == 3) { - if (rwxStr[0] == 'r') { - block.rwx |= (1 << 0); - } - if (rwxStr[1] == 'w') { - block.rwx |= (1 << 1); - } - if (rwxStr[2] == 'x') { - block.rwx |= (1 << 2); - } - } - - blockStats.blocks << block; - } - - return blockStats; -} - QList CutterCore::getXRefsForVariable(QString variableName, bool findWrites, RVA offset) { diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 66b7b0f3..09a5d767 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -658,7 +658,6 @@ public: QList getMemoryMap(); QList getAllSearch(QString searchFor, QString space, QString in); - BlockStatistics getBlockStatistics(unsigned int blocksCount); QList getBreakpoints(); QList getAllProcesses(); /** diff --git a/src/widgets/VisualNavbar.cpp b/src/widgets/VisualNavbar.cpp index 3ff9f2ac..733430ca 100644 --- a/src/widgets/VisualNavbar.cpp +++ b/src/widgets/VisualNavbar.cpp @@ -21,7 +21,8 @@ VisualNavbar::VisualNavbar(MainWindow *main, QWidget *parent) graphicsView(new QGraphicsView), seekGraphicsItem(nullptr), PCGraphicsItem(nullptr), - main(main) + main(main), + stats(nullptr, rz_core_analysis_stats_free) { Q_UNUSED(parent); @@ -114,7 +115,34 @@ void VisualNavbar::fetchAndPaintData() void VisualNavbar::fetchStats() { - stats = Core()->getBlockStatistics(statsWidth); + static const ut64 blocksCount = 2048; + + RzCoreLocked core(Core()); + stats.reset(nullptr); + RzList *list = rz_core_get_boundaries_prot(core, -1, NULL, "search"); + if (!list) { + return; + } + RzListIter *iter; + RzIOMap *map; + ut64 from = UT64_MAX; + ut64 to = 0; + CutterRzListForeach (list, iter, RzIOMap, map) { + ut64 f = rz_itv_begin(map->itv); + ut64 t = rz_itv_end(map->itv); + if (f < from) { + from = f; + } + if (t > to) { + to = t; + } + } + rz_list_free(list); + to--; // rz_core_analysis_get_stats takes inclusive ranges + if (to < from) { + return; + } + stats.reset(rz_core_analysis_get_stats(core, from, to, RZ_MAX(1, (to + 1 - from) / blocksCount))); } enum class DataType : int { Empty, Code, String, Symbol, Count }; @@ -127,17 +155,18 @@ void VisualNavbar::updateGraphicsScene() PCGraphicsItem = nullptr; graphicsScene->setBackgroundBrush(QBrush(Config()->getColor("gui.navbar.empty"))); - if (stats.to <= stats.from) { + if (!stats) { return; } int w = graphicsView->width(); int h = graphicsView->height(); - RVA totalSize = stats.to - stats.from; - RVA beginAddr = stats.from; + RVA totalSize = stats->to - stats->from + 1; + RVA beginAddr = stats->from; - double widthPerByte = (double)w / (double)totalSize; + double widthPerByte = (double)w + / (double)(totalSize ? totalSize : pow(2.0, 64.0)); // account for overflow on 2^64 auto xFromAddr = [widthPerByte, beginAddr](RVA addr) -> double { return (addr - beginAddr) * widthPerByte; }; @@ -153,24 +182,28 @@ void VisualNavbar::updateGraphicsScene() DataType lastDataType = DataType::Empty; QGraphicsRectItem *dataItem = nullptr; QRectF dataItemRect(0.0, 0.0, 0.0, h); - for (const BlockDescription &block : stats.blocks) { + for (size_t i = 0; i < rz_vector_len(&stats->blocks); i++) { + RzCoreAnalysisStatsItem *block = + reinterpret_cast(rz_vector_index_ptr(&stats->blocks, i)); + ut64 from = rz_core_analysis_stats_get_block_from(stats.get(), i); + ut64 to = rz_core_analysis_stats_get_block_to(stats.get(), i) + 1; // Keep track of where which memory segment is mapped so we are able to convert from // address to X coordinate and vice versa. XToAddress x2a; - x2a.x_start = xFromAddr(block.addr); - x2a.x_end = xFromAddr(block.addr + block.size); - x2a.address_from = block.addr; - x2a.address_to = block.addr + block.size; + x2a.x_start = xFromAddr(from); + x2a.x_end = xFromAddr(to); + x2a.address_from = from; + x2a.address_to = to; xToAddress.append(x2a); DataType dataType; - if (block.functions > 0) { + if (block->functions) { dataType = DataType::Code; - } else if (block.strings > 0) { + } else if (block->strings) { dataType = DataType::String; - } else if (block.symbols > 0) { + } else if (block->symbols) { dataType = DataType::Symbol; - } else if (block.inFunctions > 0) { + } else if (block->in_functions) { dataType = DataType::Code; } else { lastDataType = DataType::Empty; @@ -178,7 +211,7 @@ void VisualNavbar::updateGraphicsScene() } if (dataType == lastDataType) { - double r = xFromAddr(block.addr + block.size); + double r = xFromAddr(to); if (r > dataItemRect.right()) { dataItemRect.setRight(r); dataItem->setRect(dataItemRect); @@ -187,8 +220,8 @@ void VisualNavbar::updateGraphicsScene() continue; } - dataItemRect.setX(xFromAddr(block.addr)); - dataItemRect.setRight(xFromAddr(block.addr + block.size)); + dataItemRect.setX(xFromAddr(from)); + dataItemRect.setRight(xFromAddr(to)); dataItem = new QGraphicsRectItem(); dataItem->setPen(Qt::NoPen); diff --git a/src/widgets/VisualNavbar.h b/src/widgets/VisualNavbar.h index b11eb170..848f7b18 100644 --- a/src/widgets/VisualNavbar.h +++ b/src/widgets/VisualNavbar.h @@ -6,6 +6,10 @@ #include "core/Cutter.h" +#include + +#include + class MainWindow; class QGraphicsView; @@ -43,7 +47,7 @@ private: QGraphicsRectItem *PCGraphicsItem; MainWindow *main; - BlockStatistics stats; + std::unique_ptr stats; unsigned int statsWidth = 0; unsigned int previousWidth = 0; From 26e4f4acb8efef149bad4a79ad6430ff13946b84 Mon Sep 17 00:00:00 2001 From: bartoszek Date: Mon, 30 May 2022 13:04:34 +0200 Subject: [PATCH 116/240] Add missing Rizin headers in python bindings (#2943) --- src/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4fb5d4d4..47357c69 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -503,6 +503,10 @@ if(CUTTER_ENABLE_PYTHON) target_link_libraries(Cutter PRIVATE Shiboken2::libshiboken PySide2::pyside2) get_target_property(RAW_BINDINGS_INCLUDE_DIRS Cutter INCLUDE_DIRECTORIES) + if(NOT CUTTER_USE_BUNDLED_RIZIN) + get_target_property(RAW_RIZIN_INCLUDE_DIRS ${RIZIN_TARGET} INTERFACE_INCLUDE_DIRECTORIES) + list(APPEND RAW_BINDINGS_INCLUDE_DIRS "${RAW_RIZIN_INCLUDE_DIRS}") + endif() set(BINDINGS_INCLUDE_DIRS "") foreach(_dir ${RAW_BINDINGS_INCLUDE_DIRS}) string(REGEX REPLACE "\\$" "\\1" _dir ${_dir}) From 3fc3d8d878e7714233a7a0daf5dbd9461cf46fad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 30 May 2022 18:13:55 +0200 Subject: [PATCH 117/240] Fix EditVariablesDialog parenting (#2954) This fixes the dialog being placed weirdly when using the 'Y' shortcut because it was parented to the DisassemblyContextMenu, which itself might not be shown at all. --- src/menus/DisassemblyContextMenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index a60e2196..c0791493 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -875,7 +875,7 @@ void DisassemblyContextMenu::on_actionSetFunctionVarTypes_triggered() return; } - EditVariablesDialog dialog(fcn->addr, curHighlightedWord, this); + EditVariablesDialog dialog(fcn->addr, curHighlightedWord, this->mainWindow); if (dialog.empty()) { // don't show the dialog if there are no variables return; } From a630a8f5bc767b07490c8c3f8540beed6ab25f0d Mon Sep 17 00:00:00 2001 From: Islam Bassuni Date: Mon, 30 May 2022 19:34:17 +0200 Subject: [PATCH 118/240] Partially refactor Dashboard to API (#2930) Also fixes missing NX and PIC bits in Dashboard. --- src/widgets/Dashboard.cpp | 88 +++++++++++++++++++++------------------ src/widgets/Dashboard.h | 3 +- 2 files changed, 50 insertions(+), 41 deletions(-) diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index c0d0cf87..9b26927f 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -36,23 +36,8 @@ void Dashboard::updateContents() CutterJson item = docu["core"]; CutterJson item2 = docu["bin"]; - setPlainText(this->ui->fileEdit, item["file"].toString()); - setPlainText(this->ui->formatEdit, item["format"].toString()); setPlainText(this->ui->modeEdit, item["mode"].toString()); - setPlainText(this->ui->typeEdit, item["type"].toString()); - setPlainText(this->ui->sizeEdit, qhelpers::formatBytecount(item["size"].toUt64())); - setPlainText(this->ui->fdEdit, QString::number(item["fd"].toUt64())); - - setPlainText(this->ui->archEdit, item2["arch"].toString()); - setPlainText(this->ui->langEdit, item2["lang"].toString().toUpper()); - setPlainText(this->ui->classEdit, item2["class"].toString()); - setPlainText(this->ui->machineEdit, item2["machine"].toString()); - setPlainText(this->ui->osEdit, item2["os"].toString()); - setPlainText(this->ui->subsysEdit, item2["subsys"].toString()); - setPlainText(this->ui->endianEdit, item2["endian"].toString()); setPlainText(this->ui->compilationDateEdit, item2["compiled"].toString()); - setPlainText(this->ui->compilerEdit, item2["compiler"].toString()); - setPlainText(this->ui->bitsEdit, QString::number(item2["bits"].toUt64())); if (!item2["relro"].toString().isEmpty()) { QString relro = item2["relro"].toString().section(QLatin1Char(' '), 0, 0); @@ -62,21 +47,37 @@ void Dashboard::updateContents() setPlainText(this->ui->relroEdit, "N/A"); } - setPlainText(this->ui->baddrEdit, RzAddressString(item2["baddr"].toRVA())); - - // set booleans - setBool(this->ui->vaEdit, item2, "va"); - setBool(this->ui->canaryEdit, item2, "canary"); - setBool(this->ui->cryptoEdit, item2, "crypto"); - setBool(this->ui->nxEdit, item2, "nx"); - setBool(this->ui->picEdit, item2, "pic"); - setBool(this->ui->staticEdit, item2, "static"); - setBool(this->ui->strippedEdit, item2, "stripped"); - setBool(this->ui->relocsEdit, item2, "relocs"); - // Add file hashes, analysis info and libraries RzCoreLocked core(Core()); RzBinFile *bf = rz_bin_cur(core->bin); + RzBinInfo *binInfo = rz_bin_get_info(core->bin); + + setPlainText(ui->fileEdit, binInfo ? binInfo->file : ""); + setPlainText(ui->formatEdit, binInfo ? binInfo->rclass : ""); + setPlainText(ui->typeEdit, binInfo ? binInfo->type : ""); + setPlainText(ui->archEdit, binInfo ? binInfo->arch : ""); + setPlainText(ui->langEdit, binInfo ? binInfo->lang : ""); + setPlainText(ui->classEdit, binInfo ? binInfo->bclass : ""); + setPlainText(ui->machineEdit, binInfo ? binInfo->machine : ""); + setPlainText(ui->osEdit, binInfo ? binInfo->os : ""); + setPlainText(ui->subsysEdit, binInfo ? binInfo->subsystem : ""); + setPlainText(ui->compilerEdit, binInfo ? binInfo->compiler : ""); + setPlainText(ui->bitsEdit, binInfo ? QString::number(binInfo->bits) : ""); + setPlainText(ui->baddrEdit, binInfo ? RzAddressString(rz_bin_file_get_baddr(bf)) : ""); + setPlainText(ui->sizeEdit, binInfo ? qhelpers::formatBytecount(bf->size) : ""); + setPlainText(ui->fdEdit, binInfo ? QString::number(bf->fd) : ""); + + // Setting the value of "Endianness" + const char *endian = binInfo ? (binInfo->big_endian ? "BE" : "LE") : ""; + setPlainText(this->ui->endianEdit, endian); + + // Setting boolean values + setRzBinInfo(binInfo); + + // Setting the value of "static" + int static_value = rz_bin_is_static(core->bin); + setPlainText(ui->staticEdit, tr(setBoolText(static_value))); + RzList *hashes = rz_bin_file_compute_hashes(core->bin, bf, UT64_MAX); // Delete hashesWidget if it isn't null to avoid duplicate components @@ -222,19 +223,26 @@ void Dashboard::setPlainText(QLineEdit *textBox, const QString &text) } /** - * @brief Set the text of a QLineEdit as True, False or N/A if it does not exist - * @param textBox - * @param isTrue + * @brief Setting boolean values of binary information in dashboard + * @param RzBinInfo */ -void Dashboard::setBool(QLineEdit *textBox, const CutterJson &jsonObject, const char *key) +void Dashboard::setRzBinInfo(RzBinInfo *binInfo) { - if (jsonObject[key].valid()) { - if (jsonObject[key].toBool()) { - setPlainText(textBox, tr("True")); - } else { - setPlainText(textBox, tr("False")); - } - } else { - setPlainText(textBox, tr("N/A")); - } + setPlainText(ui->vaEdit, binInfo ? setBoolText(binInfo->has_va) : ""); + setPlainText(ui->canaryEdit, binInfo ? setBoolText(binInfo->has_canary) : ""); + setPlainText(ui->cryptoEdit, binInfo ? setBoolText(binInfo->has_crypto) : ""); + setPlainText(ui->nxEdit, binInfo ? setBoolText(binInfo->has_nx) : ""); + setPlainText(ui->picEdit, binInfo ? setBoolText(binInfo->has_pi) : ""); + setPlainText(ui->strippedEdit, + binInfo ? setBoolText(RZ_BIN_DBG_STRIPPED & binInfo->dbg_info) : ""); + setPlainText(ui->relocsEdit, binInfo ? setBoolText(RZ_BIN_DBG_RELOCS & binInfo->dbg_info) : ""); +} + +/** + * @brief Set the text of a QLineEdit as True, False + * @param boolean value + */ +const char *Dashboard::setBoolText(bool value) +{ + return value ? "True" : "False"; } diff --git a/src/widgets/Dashboard.h b/src/widgets/Dashboard.h index 61a2c677..a7ee5c15 100644 --- a/src/widgets/Dashboard.h +++ b/src/widgets/Dashboard.h @@ -33,7 +33,8 @@ private slots: private: std::unique_ptr ui; void setPlainText(QLineEdit *textBox, const QString &text); - void setBool(QLineEdit *textBox, const CutterJson &jsonObject, const char *key); + void setRzBinInfo(RzBinInfo *binInfo); + const char *setBoolText(bool value); QWidget *hashesWidget = nullptr; }; From 2e6fd46127e9a5365293d7ab8bfa60225627b402 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 30 May 2022 19:34:33 +0200 Subject: [PATCH 119/240] Fix null deref in strings loading without any file (#2955) --- src/core/Cutter.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index ee27caaa..0f31eddd 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -542,10 +542,7 @@ CutterJson CutterCore::cmdjTask(const QString &str) RizinCmdTask task(str); task.startTask(); task.joinTask(); - const char *res = task.getResultRaw(); - char *copy = static_cast(rz_mem_alloc(strlen(res) + 1)); - strcpy(copy, res); - return parseJson(copy, str); + return task.getResultJson(); } CutterJson CutterCore::parseJson(char *res, const char *cmd) From 247ab94b71b271ca8dfa76ff66a78374a37e9951 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Mon, 6 Jun 2022 11:27:13 +0200 Subject: [PATCH 120/240] Download and install sigdb option (#2949) * Download and install sigdb option and disable swift demangler when libswift is installed * Remove dir.prefix and use rz_core_analysis_sigdb_list for sigdb * Use a different color for flirts * Updated to rizin dev * Use rz_path_set_prefix to set the prefix path on OSX bundle --- .github/workflows/ccpp.yml | 3 ++ CMakeLists.txt | 4 ++ cmake/BundledRizin.cmake | 8 ++++ dist/CMakeLists.txt | 8 +--- rizin | 2 +- src/CutterApplication.cpp | 4 +- src/common/ColorThemeWorker.cpp | 4 +- src/common/Configuration.cpp | 2 + src/core/Cutter.cpp | 73 ++++++++------------------------- src/widgets/FunctionsWidget.cpp | 2 + 10 files changed, 45 insertions(+), 65 deletions(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 64a3f7f6..a1aec8cb 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -120,6 +120,7 @@ jobs: -DCUTTER_USE_BUNDLED_RIZIN=ON \ -DCUTTER_APPIMAGE_BUILD=ON \ -DCUTTER_ENABLE_PACKAGING=ON \ + -DCUTTER_ENABLE_SIGDB=ON \ -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON \ -DCUTTER_PACKAGE_RZ_GHIDRA=ON \ -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \ @@ -185,6 +186,7 @@ jobs: -DCUTTER_ENABLE_CRASH_REPORTS=ON \ -DCUTTER_USE_BUNDLED_RIZIN=ON \ -DCUTTER_ENABLE_PACKAGING=ON \ + -DCUTTER_ENABLE_SIGDB=ON \ -DCUTTER_PACKAGE_DEPENDENCIES=ON \ -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON \ -DCUTTER_PACKAGE_RZ_GHIDRA=ON \ @@ -225,6 +227,7 @@ jobs: -DCUTTER_ENABLE_PYTHON=ON ^ -DCUTTER_ENABLE_PYTHON_BINDINGS=ON ^ -DCUTTER_ENABLE_PACKAGING=ON ^ + -DCUTTER_ENABLE_SIGDB=ON ^ -DCUTTER_PACKAGE_DEPENDENCIES=ON ^ -DCUTTER_PACKAGE_RZ_GHIDRA=ON ^ -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON ^ diff --git a/CMakeLists.txt b/CMakeLists.txt index 991368ec..9498c796 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ set(SHIBOKEN_EXTRA_OPTIONS "" CACHE STRING "Extra options for shiboken generator set(CUTTER_EXTRA_PLUGIN_DIRS "" CACHE STRING "List of addition plugin locations") option(CUTTER_ENABLE_DEPENDENCY_DOWNLOADS "Enable downloading of dependencies. Setting to OFF doesn't affect any downloads done by rizin build." OFF) option(CUTTER_ENABLE_PACKAGING "Enable building platform-specific packages for distributing" OFF) +option(CUTTER_ENABLE_SIGDB "Downloads and installs sigdb (only available when CUTTER_USE_BUNDLED_RIZIN=ON)." OFF) option(CUTTER_PACKAGE_DEPENDENCIES "During install step include the third party dependencies." OFF) option(CUTTER_PACKAGE_RZ_GHIDRA "Compile and install rz-ghidra during install step." OFF) option(CUTTER_PACKAGE_RZ_LIBSWIFT, "Compile and install rz-libswift demangler during the install step." OFF) @@ -123,6 +124,9 @@ message(STATUS "") message(STATUS "Building Cutter version ${CUTTER_VERSION_FULL}") message(STATUS "Options:") message(STATUS "- Bundled rizin: ${CUTTER_USE_BUNDLED_RIZIN}") +if(CUTTER_USE_BUNDLED_RIZIN) + message(STATUS "- Bundled sigdb: ${CUTTER_ENABLE_SIGDB}") +endif() message(STATUS "- Python: ${CUTTER_ENABLE_PYTHON}") message(STATUS "- Python Bindings: ${CUTTER_ENABLE_PYTHON_BINDINGS}") message(STATUS "- Crash Handling: ${CUTTER_ENABLE_CRASH_REPORTS}") diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index 83e4c128..7955c279 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -18,6 +18,14 @@ if (CUTTER_ENABLE_PACKAGING) list(APPEND MESON_OPTIONS "-Dportable=true") endif() +if (CUTTER_ENABLE_SIGDB) + list(APPEND MESON_OPTIONS "-Dinstall_sigdb=true") +endif() + +if (CUTTER_PACKAGE_RZ_LIBSWIFT AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) + list(APPEND MESON_OPTIONS "-Duse_swift_demangler=false") +endif() + find_program(MESON meson) if(NOT MESON) message(FATAL_ERROR "Failed to find meson, which is required to build bundled rizin") diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index 6ce64463..fa4b80e5 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -92,7 +92,7 @@ if(APPLE) get_filename_component(QT_PREFIX "${MACDEPLOYQT_PATH}/../.." ABSOLUTE) list(APPEND RZ_GHIDRA_PREFIX_PATH "${QT_PREFIX}") - set(RIZIN_INSTALL_PLUGDIR "share/rizin/plugins") # escaped backslash on purpose, should be evaluated later + set(RIZIN_INSTALL_PLUGDIR "lib/rizin/plugins") # escaped backslash on purpose, should be evaluated later if (CUTTER_PACKAGE_JSDEC AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) install(CODE " @@ -139,11 +139,7 @@ if(CUTTER_PACKAGE_RZ_GHIDRA) INSTALL_COMMAND "" ) endif() - if (WIN32) - set (GHIDRA_OPTIONS " - \"-DRIZIN_INSTALL_PLUGDIR=\${CMAKE_INSTALL_PREFIX}/${RIZIN_INSTALL_PLUGDIR}\" - -DCUTTER_INSTALL_PLUGDIR=plugins/native") - elseif (APPLE) + if (WIN32 OR APPLE) set (GHIDRA_OPTIONS " \"-DRIZIN_INSTALL_PLUGDIR=\${CMAKE_INSTALL_PREFIX}/${RIZIN_INSTALL_PLUGDIR}\" -DCUTTER_INSTALL_PLUGDIR=plugins/native") diff --git a/rizin b/rizin index 0950e823..7665d0f3 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 0950e823a4502677cbf77cfd0266e8de64875fc0 +Subproject commit 7665d0f30ef7771b305329502d94842ec4a97a62 diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index 2dccd156..bfd7679a 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -177,11 +177,11 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc { auto rzprefix = QDir(QCoreApplication::applicationDirPath()); // Contents/MacOS rzprefix.cdUp(); // Contents - rzprefix.cd("Resources"); // Contents/Resources/rz + rzprefix.cd("Resources"); // Contents/Resources/ auto sleighHome = rzprefix; sleighHome.cd( - "share/rizin/plugins/rz_ghidra_sleigh"); // Contents/Resources/rz/share/rizin/plugins/rz_ghidra_sleigh + "lib/rizin/plugins/rz_ghidra_sleigh"); // Contents/Resources/lib/rizin/plugins/rz_ghidra_sleigh Core()->setConfig("ghidra.sleighhome", sleighHome.absolutePath()); } #endif diff --git a/src/common/ColorThemeWorker.cpp b/src/common/ColorThemeWorker.cpp index c4abfd5c..a9e592ba 100644 --- a/src/common/ColorThemeWorker.cpp +++ b/src/common/ColorThemeWorker.cpp @@ -37,7 +37,8 @@ ColorThemeWorker::ColorThemeWorker(QObject *parent) : QObject(parent) QDir().mkpath(customRzThemesLocationPath); } - QDir currDir { QStringLiteral("%1%2%3").arg(rz_path_prefix(nullptr), RZ_SYS_DIR, RZ_THEMES) }; + char *theme_dir = rz_path_prefix(RZ_THEMES); + QDir currDir { theme_dir }; if (currDir.exists()) { standardRzThemesLocationPath = currDir.absolutePath(); } else { @@ -46,6 +47,7 @@ ColorThemeWorker::ColorThemeWorker(QObject *parent) : QObject(parent) "Most likely, Rizin is not properly installed.") .arg(currDir.path())); } + free(theme_dir); } QColor ColorThemeWorker::mergeColors(const QColor &upper, const QColor &lower) const diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 5239ad6b..25d5907a 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -46,6 +46,8 @@ const QHash> Configuration::cutterOptionColor { { DarkFlag, QColor(0x9b, 0x9b, 0x9b) }, { LightFlag, QColor(0x9b, 0x9b, 0x9b) } } }, { "gui.main", { { DarkFlag, QColor(0x21, 0xd8, 0x93) }, { LightFlag, QColor(0x00, 0x80, 0x00) } } }, + { "gui.flirt", + { { DarkFlag, QColor(0xd8, 0xbb, 0x21) }, { LightFlag, QColor(0xf1, 0xc4, 0x0f) } } }, { "gui.item_unsafe", { { DarkFlag, QColor(0xff, 0x81, 0x7b) }, { LightFlag, QColor(0xff, 0x81, 0x7b) } } }, { "gui.navbar.seek", diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 0f31eddd..161916cd 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -188,11 +188,13 @@ CutterCore *CutterCore::instance() void CutterCore::initialize(bool loadPlugins) { - auto prefix = QDir(QCoreApplication::applicationDirPath()); - -#if defined(CUTTER_ENABLE_PACKAGING) && defined(Q_OS_WIN) - auto prefixBytes = prefix.absolutePath().toUtf8(); - rz_path_prefix(prefixBytes.constData()); +#if defined(MACOS_RZ_BUNDLED) + auto app_path = QDir(QCoreApplication::applicationDirPath()); + app_path.cdUp(); + app_path.cd("Resources"); + qInfo() << "Setting Rizin prefix =" << app_path.absolutePath() + << " for macOS Application Bundle."; + rz_path_set_prefix(app_path.absolutePath().toUtf8().constData()); #endif rz_cons_new(); // initialize console @@ -203,34 +205,11 @@ void CutterCore::initialize(bool loadPlugins) rz_event_hook(core_->analysis->ev, RZ_EVENT_ALL, cutterREventCallback, this); -#if defined(APPIMAGE) || defined(MACOS_RZ_BUNDLED) -# ifdef APPIMAGE - // Executable is in appdir/bin - prefix.cdUp(); - qInfo() << "Setting Rizin prefix =" << prefix.absolutePath() << " for AppImage."; -# else // MACOS_RZ_BUNDLED - // Executable is in Contents/MacOS, prefix is Contents/Resources/rz - prefix.cdUp(); - prefix.cd("Resources"); - qInfo() << "Setting Rizin prefix =" << prefix.absolutePath() - << " for macOS Application Bundle."; - setConfig("dir.prefix", prefix.absolutePath()); -# endif - - auto pluginsDir = prefix; - if (pluginsDir.cd("share/rizin/plugins")) { - qInfo() << "Setting Rizin plugins dir =" << pluginsDir.absolutePath(); - setConfig("dir.plugins", pluginsDir.absolutePath()); - } else { - qInfo() << "Rizin plugins dir under" << pluginsDir.absolutePath() << "does not exist!"; - } -#endif - - if (!loadPlugins) { - setConfig("cfg.plugins", 0); - } - if (getConfigi("cfg.plugins")) { + if (loadPlugins) { + setConfig("cfg.plugins", true); rz_core_loadlibs(this->core_, RZ_CORE_LOADLIBS_ALL); + } else { + setConfig("cfg.plugins", false); } // IMPLICIT rz_bin_iobind (core_->bin, core_->io); @@ -3166,10 +3145,16 @@ QList CutterCore::getAllHeaders() return ret; } -static void sigdb_insert_element_into_qlist(RzList *list, QList &sigdb) +QList CutterCore::getSignaturesDB() { + CORE_LOCK(); + void *ptr = NULL; RzListIter *iter = NULL; + QList sigdb; + + RzList *list = rz_core_analysis_sigdb_list(core, true); + rz_list_foreach(list, iter, ptr) { RzSigDBEntry *sig = static_cast(ptr); @@ -3185,28 +3170,6 @@ static void sigdb_insert_element_into_qlist(RzList *list, QList CutterCore::getSignaturesDB() -{ - CORE_LOCK(); - QList sigdb; - RzList *list = nullptr; - - char *system_sigdb = rz_path_system(RZ_SIGDB); - if (RZ_STR_ISNOTEMPTY(system_sigdb) && rz_file_is_directory(system_sigdb)) { - list = rz_sign_sigdb_load_database(system_sigdb, true); - sigdb_insert_element_into_qlist(list, sigdb); - } - free(system_sigdb); - - const char *sigdb_path = rz_config_get(core->config, "flirt.sigdb.path"); - if (RZ_STR_ISEMPTY(sigdb_path)) { - return sigdb; - } - - list = rz_sign_sigdb_load_database(sigdb_path, true); - sigdb_insert_element_into_qlist(list, sigdb); return sigdb; } diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index ab92ecd9..6324467b 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -274,6 +274,8 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const return QVariant(ConfigColor("gui.imports")); } else if (functionIsMain(function.offset)) { return QVariant(ConfigColor("gui.main")); + } else if (function.name.startsWith("flirt.")) { + return QVariant(ConfigColor("gui.flirt")); } return QVariant(this->property("color")); From 90608117c999150e14a2ff41213eda271b7e6787 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Wed, 8 Jun 2022 01:18:43 +0200 Subject: [PATCH 121/240] Yara plugin + fix linuxdeployqt plugins (#2924) --- .github/workflows/ccpp.yml | 9 +++-- CMakeLists.txt | 9 +++++ dist/CMakeLists.txt | 64 +++++++++++++++++++++++++++------- dist/MacOSSetupBundle.cmake.in | 3 ++ dist/bundle_rz_libswift.ps1 | 2 +- dist/bundle_rz_libyara.ps1 | 26 ++++++++++++++ rizin | 2 +- scripts/rz-libyara.sh | 25 +++++++++++++ src/CutterApplication.cpp | 7 +--- src/plugins/PluginManager.cpp | 2 ++ 10 files changed, 123 insertions(+), 26 deletions(-) create mode 100644 dist/bundle_rz_libyara.ps1 create mode 100755 scripts/rz-libyara.sh diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index a1aec8cb..a1c8e0c5 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -124,6 +124,7 @@ jobs: -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON \ -DCUTTER_PACKAGE_RZ_GHIDRA=ON \ -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \ + -DCUTTER_PACKAGE_RZ_LIBYARA=ON \ -DCMAKE_INSTALL_PREFIX=appdir/usr \ -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON \ .. @@ -142,20 +143,16 @@ jobs: ninja install "../scripts/appimage_embed_python.sh" appdir APP_PREFIX=`pwd`/appdir/usr - # export LD_LIBRARY_PATH=${APP_PREFIX}/lib:$Shiboken2_ROOT/lib + export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$APP_PREFIX/lib/rizin/plugins" export PATH=$PATH:${APP_PREFIX}/bin - "../scripts/jsdec.sh" --prefix=`pwd`/appdir/usr wget -c "https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage" chmod a+x linuxdeployqt*.AppImage rm -fv "../cutter-deps/qt/plugins/imageformats/libqjp2.so" - # ./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop -executable=./appdir/usr/bin/python3 -bundle-non-qt-libs -no-strip -exclude-libs=libnss3.so,libnssutil3.so,libqjp2.so -ignore-glob=usr/lib/python3.9/**/* -verbose=2 - # exclude librzghidra cutter plugin because cutter and rz plugin is loaded manuallly as they are plugins linuxdeployqt doesn't know this ./linuxdeployqt*.AppImage ./appdir/usr/share/applications/*.desktop \ -executable=./appdir/usr/bin/python3 \ -appimage \ -no-strip -exclude-libs=libnss3.so,libnssutil3.so,libqjp2.so \ -ignore-glob=usr/lib/python3.9/**/* \ - -ignore-glob=usr/share/rizin/cutter/plugins/native/librz_ghidra_cutter.so \ -verbose=2 find ./appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " " -f 2-3 | sort | uniq export APPIMAGE_FILE="Cutter-${PACKAGE_ID}-x64.Linux.AppImage" @@ -192,6 +189,7 @@ jobs: -DCUTTER_PACKAGE_RZ_GHIDRA=ON \ -DCUTTER_PACKAGE_JSDEC=ON \ -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \ + -DCUTTER_PACKAGE_RZ_LIBYARA=ON \ -DCPACK_PACKAGE_FILE_NAME="$PACKAGE_NAME" \ -DCMAKE_FRAMEWORK_PATH="$BREAKPAD_FRAMEWORK_DIR" \ -DCPACK_BUNDLE_APPLE_CERT_APP="-" \ @@ -231,6 +229,7 @@ jobs: -DCUTTER_PACKAGE_DEPENDENCIES=ON ^ -DCUTTER_PACKAGE_RZ_GHIDRA=ON ^ -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON ^ + -DCUTTER_PACKAGE_RZ_LIBYARA=ON ^ -DCUTTER_PACKAGE_JSDEC=ON ^ -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON ^ -DCUTTER_ENABLE_CRASH_REPORTS=ON ^ diff --git a/CMakeLists.txt b/CMakeLists.txt index 9498c796..034478ca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ option(CUTTER_ENABLE_SIGDB "Downloads and installs sigdb (only available when CU option(CUTTER_PACKAGE_DEPENDENCIES "During install step include the third party dependencies." OFF) option(CUTTER_PACKAGE_RZ_GHIDRA "Compile and install rz-ghidra during install step." OFF) option(CUTTER_PACKAGE_RZ_LIBSWIFT, "Compile and install rz-libswift demangler during the install step." OFF) +option(CUTTER_PACKAGE_RZ_LIBYARA, "Compile and install rz-libyara during the install step." OFF) option(CUTTER_PACKAGE_JSDEC "Compile and install jsdec during install step." OFF) OPTION(CUTTER_QT6 "Use QT6" OFF) @@ -132,6 +133,14 @@ message(STATUS "- Python Bindings: ${CUTTER_ENABLE_PYTHON_BINDINGS}") message(STATUS "- Crash Handling: ${CUTTER_ENABLE_CRASH_REPORTS}") message(STATUS "- KSyntaxHighlighting: ${KSYNTAXHIGHLIGHTING_STATUS}") message(STATUS "- Graphviz: ${CUTTER_ENABLE_GRAPHVIZ}") +message(STATUS "- Downloads dependencies: ${CUTTER_ENABLE_DEPENDENCY_DOWNLOADS}") +message(STATUS "- Enable Packaging: ${CUTTER_ENABLE_PACKAGING}") +message(STATUS "- Package Dependencies: ${CUTTER_PACKAGE_DEPENDENCIES}") +message(STATUS "- Package RzGhidra: ${CUTTER_PACKAGE_RZ_GHIDRA}") +message(STATUS "- Package RzLibSwift: ${CUTTER_PACKAGE_RZ_LIBSWIFT}") +message(STATUS "- Package RzLibYara: ${CUTTER_PACKAGE_RZ_LIBYARA}") +message(STATUS "- Package JSDec: ${CUTTER_PACKAGE_JSDEC}") +message(STATUS "- QT6: ${CUTTER_QT6}") message(STATUS "") add_subdirectory(src) diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index fa4b80e5..ee962d2e 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -28,7 +28,7 @@ if(WIN32) WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE SCRIPT_RESULT) if (SCRIPT_RESULT) - message(FATAL_ERROR \"Failed to package jsdec\") + message(FATAL_ERROR \"Failed to package jsdec (returned \${SCRIPT_RESULT})\") endif() ") endif() @@ -40,7 +40,22 @@ if(WIN32) WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE SCRIPT_RESULT) if (SCRIPT_RESULT) - message(FATAL_ERROR \"Failed to package rz-libswift\") + message(FATAL_ERROR \"Failed to package rz-libswift (returned \${SCRIPT_RESULT})\") + endif() + ") + endif() + if (CUTTER_PACKAGE_RZ_LIBYARA AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) + install(CODE " + set(ENV{RZ_PREFIX} \"\${CMAKE_INSTALL_PREFIX}\") + set(ENV{PATH} \"\${CMAKE_INSTALL_PREFIX};\$ENV{PATH}\") + execute_process(COMMAND powershell + \"${CMAKE_CURRENT_SOURCE_DIR}/bundle_rz_libyara.ps1\" + \"\${CMAKE_INSTALL_PREFIX}\" + \"-DCUTTER_INSTALL_PLUGDIR=plugins/native\" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE SCRIPT_RESULT) + if (SCRIPT_RESULT) + message(FATAL_ERROR \"Failed to package rz_libyara (returned \${SCRIPT_RESULT})\") endif() ") endif() @@ -93,29 +108,52 @@ if(APPLE) get_filename_component(QT_PREFIX "${MACDEPLOYQT_PATH}/../.." ABSOLUTE) list(APPEND RZ_GHIDRA_PREFIX_PATH "${QT_PREFIX}") set(RIZIN_INSTALL_PLUGDIR "lib/rizin/plugins") # escaped backslash on purpose, should be evaluated later +endif() - if (CUTTER_PACKAGE_JSDEC AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) +################################################ +# macOS + Linux +################################################ + +if(CUTTER_ENABLE_DEPENDENCY_DOWNLOADS AND (NOT WIN32)) + if (CUTTER_PACKAGE_JSDEC) install(CODE " - execute_process(COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/jsdec.sh\" --pkg-config-path=\${CMAKE_INSTALL_PREFIX}/lib/pkgconfig --prefix=\${CMAKE_INSTALL_PREFIX} + execute_process(COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/jsdec.sh\" + --pkg-config-path=\${CMAKE_INSTALL_PREFIX}/lib/pkgconfig --prefix=\${CMAKE_INSTALL_PREFIX} WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE SCRIPT_RESULT) if (SCRIPT_RESULT) - message(FATAL_ERROR \"Failed to package jsdec\") + message(FATAL_ERROR \"Failed to package jsdec (returned \${SCRIPT_RESULT})\") endif() ") endif() - - if (CUTTER_PACKAGE_RZ_LIBSWIFT AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) + if (CUTTER_PACKAGE_RZ_LIBSWIFT) install(CODE " - execute_process(COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/rz-libswift.sh\" --pkg-config-path=\${CMAKE_INSTALL_PREFIX}/lib/pkgconfig --prefix=\${CMAKE_INSTALL_PREFIX} + execute_process(COMMAND \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/rz-libswift.sh\" + --pkg-config-path=\${CMAKE_INSTALL_PREFIX}/lib/pkgconfig --prefix=\${CMAKE_INSTALL_PREFIX} WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE SCRIPT_RESULT) if (SCRIPT_RESULT) - message(FATAL_ERROR \"Failed to package rz-libswift\") + message(FATAL_ERROR \"Failed to package rz-libswift (returned \${SCRIPT_RESULT})\") + endif() + ") + endif() + if (CUTTER_PACKAGE_RZ_LIBYARA) + if(APPLE) + set (YARA_PLUGIN_OPTIONS "-DCUTTER_INSTALL_PLUGDIR=plugins/native") + else() + set (YARA_PLUGIN_OPTIONS "") + endif() + install(CODE " + execute_process(COMMAND + \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/rz-libyara.sh\" + \"\${CMAKE_INSTALL_PREFIX}\" \"${YARA_PLUGIN_OPTIONS}\" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE SCRIPT_RESULT) + if (SCRIPT_RESULT) + message(FATAL_ERROR \"Failed to package rz-libyara (returned \${SCRIPT_RESULT})\") endif() ") endif() - endif() ################################################ @@ -144,7 +182,7 @@ if(CUTTER_PACKAGE_RZ_GHIDRA) \"-DRIZIN_INSTALL_PLUGDIR=\${CMAKE_INSTALL_PREFIX}/${RIZIN_INSTALL_PLUGDIR}\" -DCUTTER_INSTALL_PLUGDIR=plugins/native") else() - set (GHIDRA_OPTIONS "") + set (GHIDRA_OPTIONS "-DCUTTER_INSTALL_PLUGDIR=\${CMAKE_INSTALL_PREFIX}/share/rizin/cutter/plugins/native") endif() install(CODE " execute_process( @@ -161,14 +199,14 @@ if(CUTTER_PACKAGE_RZ_GHIDRA) -G Ninja ) if (SCRIPT_RESULT) - message(FATAL_ERROR \"Failed to configure rz-ghidra\") + message(FATAL_ERROR \"Failed to configure rz-ghidra (returned \${SCRIPT_RESULT})\") endif() execute_process(WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/rz-ghidra-prefix/src/rz-ghidra-build RESULT_VARIABLE SCRIPT_RESULT COMMAND \${CMAKE_COMMAND} --build . --target install ) if (SCRIPT_RESULT) - message(FATAL_ERROR \"Failed to install rz-ghidra plugin\") + message(FATAL_ERROR \"Failed to install rz-ghidra plugin (returned \${SCRIPT_RESULT})\") endif() ") endif() diff --git a/dist/MacOSSetupBundle.cmake.in b/dist/MacOSSetupBundle.cmake.in index 88bd6fd8..ff8bdb35 100644 --- a/dist/MacOSSetupBundle.cmake.in +++ b/dist/MacOSSetupBundle.cmake.in @@ -60,6 +60,9 @@ run_or_die(COMMAND install_name_tool run_or_die(COMMAND install_name_tool -add_rpath "@executable_path/../Resources/lib" "${EXECUTABLE_DIR}/cutter") +run_or_die(COMMAND install_name_tool + -add_rpath "@executable_path/../Resources/lib/rizin/plugins" + "${EXECUTABLE_DIR}/cutter") set(MACDEPLOYQT_COMMAND "${MACDEPLOYQT_PATH}" "${BUNDLE_PATH}" "-verbose=2" "-libpath=${CMAKE_INSTALL_PREFIX}/lib") message("Running macdeployqt \"${MACDEPLOYQT_COMMAND}\"") diff --git a/dist/bundle_rz_libswift.ps1 b/dist/bundle_rz_libswift.ps1 index 12928c93..9fec607c 100644 --- a/dist/bundle_rz_libswift.ps1 +++ b/dist/bundle_rz_libswift.ps1 @@ -13,4 +13,4 @@ if(![System.IO.File]::Exists($pathdll)) { ls "$dist/lib/plugins/" throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll)) } -Remove-Item -Recurse -Force $dist/lib/plugins/libswift.lib +Remove-Item -Recurse -Force $dist/lib/plugins/swift.lib diff --git a/dist/bundle_rz_libyara.ps1 b/dist/bundle_rz_libyara.ps1 new file mode 100644 index 00000000..c3309b94 --- /dev/null +++ b/dist/bundle_rz_libyara.ps1 @@ -0,0 +1,26 @@ +$dist = $args[0] +$cmake_opts = $args[1] +$python = Split-Path((Get-Command python.exe).Path) + +if (-not (Test-Path -Path 'rz_libyara' -PathType Container)) { + git clone https://github.com/rizinorg/rz-libyara.git --depth 1 rz_libyara + git -C rz_libyara submodule init + git -C rz_libyara submodule update +} +cd rz_libyara +& meson.exe --buildtype=release --prefix=$dist build +ninja -C build install +$pathdll = "$dist/lib/plugins/rz_yara.dll" +if(![System.IO.File]::Exists($pathdll)) { + type build/meson-logs/meson-log.txt + ls "$dist/lib/plugins/" + throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll)) +} +Remove-Item -Recurse -Force $dist/lib/plugins/rz_yara.lib + +cd cutter-plugin +mkdir build +cd build +cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DRIZIN_INSTALL_PLUGDIR="../build" -DCMAKE_INSTALL_PREFIX="$dist" $cmake_opts .. +ninja +ninja install diff --git a/rizin b/rizin index 7665d0f3..1a0ce1fa 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 7665d0f30ef7771b305329502d94842ec4a97a62 +Subproject commit 1a0ce1faa3b552c4f1756d377ffa5973a9a358bf diff --git a/scripts/rz-libyara.sh b/scripts/rz-libyara.sh new file mode 100755 index 00000000..f316f2c5 --- /dev/null +++ b/scripts/rz-libyara.sh @@ -0,0 +1,25 @@ +#!/bin/bash +set -e + +SCRIPTPATH=$(realpath "$(dirname "${BASH_SOURCE[0]}")") +INSTALL_PREFIX="$1" +EXTRA_CMAKE_OPTS="$2" + +cd "$SCRIPTPATH/.." + +if [[ ! -d rz_libyara ]]; then + git clone https://github.com/rizinorg/rz-libyara.git --depth 1 rz_libyara + git -C rz_libyara submodule init + git -C rz_libyara submodule update +fi + +cd rz_libyara + +meson --buildtype=release --pkg-config-path="$INSTALL_PREFIX/lib/pkgconfig" --prefix="$INSTALL_PREFIX" build +ninja -C build install + +cd cutter-plugin +mkdir build && cd build +cmake -G Ninja -DRIZIN_INSTALL_PLUGDIR="../build" -DCMAKE_INSTALL_PREFIX="$INSTALL_PREFIX" $EXTRA_CMAKE_OPTS .. +ninja +ninja install diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index bfd7679a..9d4d4dff 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -163,13 +163,8 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc appdir.cdUp(); // appdir auto sleighHome = appdir; - sleighHome.cd( - "share/rizin/plugins/rz_ghidra_sleigh"); // appdir/share/rizin/plugins/rz_ghidra_sleigh + sleighHome.cd("lib/rizin/plugins/rz_ghidra_sleigh/"); // appdir/lib/rizin/plugins/rz_ghidra_sleigh/ Core()->setConfig("ghidra.sleighhome", sleighHome.absolutePath()); - - auto jsdecHome = appdir; - jsdecHome.cd("share/rizin/plugins/jsdec"); // appdir/share/rizin/plugins/jsdec - qputenv("JSDEC_HOME", jsdecHome.absolutePath().toLocal8Bit()); } #endif diff --git a/src/plugins/PluginManager.cpp b/src/plugins/PluginManager.cpp index 28cffb44..ac9c6104 100644 --- a/src/plugins/PluginManager.cpp +++ b/src/plugins/PluginManager.cpp @@ -65,6 +65,7 @@ void PluginManager::loadPluginsFromDir(const QDir &pluginsDir, bool writable) nativePluginsDir.mkdir("native"); } if (nativePluginsDir.cd("native")) { + qInfo() << "Native plugins are loaded from" << nativePluginsDir.absolutePath(); loadNativePlugins(nativePluginsDir); } @@ -74,6 +75,7 @@ void PluginManager::loadPluginsFromDir(const QDir &pluginsDir, bool writable) pythonPluginsDir.mkdir("python"); } if (pythonPluginsDir.cd("python")) { + qInfo() << "Python plugins are loaded from" << pythonPluginsDir.absolutePath(); loadPythonPlugins(pythonPluginsDir.absolutePath()); } #endif From 11419f6858ca939623c551a39bada0319e6b00bd Mon Sep 17 00:00:00 2001 From: billow Date: Wed, 8 Jun 2022 08:02:26 +0800 Subject: [PATCH 122/240] Convert Rizin command calls to te Rizin APIs (#2960) * Convert `iCj` call to the API * Convert `icj` call to the API * Convert `iij` call to the API * Convert `iej` call to the API * Convert `CClj` call to the API * Convert `iEj` call to the API * Convert 'ihj' call to the API * Convert 'iSSj' call to the API --- src/core/Cutter.cpp | 275 +++++++++++++++++++++++++------------- src/core/Cutter.h | 2 +- src/widgets/Dashboard.cpp | 4 +- 3 files changed, 188 insertions(+), 93 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 161916cd..80e41699 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1415,9 +1415,19 @@ CutterJson CutterCore::getFileVersionInfo() return cmdj("iVj"); } -CutterJson CutterCore::getSignatureInfo() +QString CutterCore::getSignatureInfo() { - return cmdj("iCj"); + CORE_LOCK(); + RzBinFile *cur = rz_bin_cur(core->bin); + RzBinPlugin *plg = rz_bin_file_cur_plugin(cur); + if (!plg || !plg->signature) { + return {}; + } + char *signature = plg->signature(cur, true); + if (!signature) { + return {}; + } + return fromOwnedCharPtr(signature); } // Utility function to check if a telescoped item exists and add it with prefixes to the desc @@ -3049,25 +3059,64 @@ QList CutterCore::getAllFunctions() return funcList; } +static inline uint64_t rva(RzBinObject *o, uint64_t paddr, uint64_t vaddr, int va) +{ + return va ? rz_bin_object_get_vaddr(o, paddr, vaddr) : paddr; +} + QList CutterCore::getAllImports() { CORE_LOCK(); - QList ret; - - for (CutterJson importObject : cmdj("iij")) { - ImportDescription import; - - import.plt = importObject[RJsonKey::plt].toRVA(); - import.ordinal = importObject[RJsonKey::ordinal].toSt64(); - import.bind = importObject[RJsonKey::bind].toString(); - import.type = importObject[RJsonKey::type].toString(); - import.libname = importObject[RJsonKey::libname].toString(); - import.name = importObject[RJsonKey::name].toString(); - - ret << import; + RzBinFile *bf = rz_bin_cur(core->bin); + if (!bf) { + return {}; + } + const RzList *imports = rz_bin_object_get_imports(bf->o); + if (!imports) { + return {}; } - return ret; + QList qList; + RzBinImport *import; + RzListIter *iter; + bool va = core->io->va || core->bin->is_debugger; + int bin_demangle = getConfigi("bin.demangle"); + int keep_lib = getConfigi("bin.demangle.libs"); + CutterRzListForeach (imports, iter, RzBinImport, import) { + if (RZ_STR_ISEMPTY(import->name)) { + continue; + } + + ImportDescription importDescription; + + RzBinSymbol *sym = rz_bin_object_get_symbol_of_import(bf->o, import); + ut64 addr = sym ? rva(bf->o, sym->paddr, sym->vaddr, va) : UT64_MAX; + QString name { import->name }; + if (RZ_STR_ISNOTEMPTY(import->classname)) { + name = QString("%1.%2").arg(import->classname, import->name); + } + if (bin_demangle) { + char *dname = rz_bin_demangle(bf, NULL, name.toUtf8().constData(), + importDescription.plt, keep_lib); + if (dname) { + name = fromOwnedCharPtr(dname); + } + } + if (core->bin->prefix) { + name = QString("%1.%2").arg(core->bin->prefix, name); + } + + importDescription.ordinal = (int)import->ordinal; + importDescription.bind = import->bind; + importDescription.type = import->type; + importDescription.libname = import->libname; + importDescription.name = name; + importDescription.plt = addr; + + qList << importDescription; + } + + return qList; } QList CutterCore::getAllExports() @@ -3129,16 +3178,24 @@ QList CutterCore::getAllSymbols() QList CutterCore::getAllHeaders() { CORE_LOCK(); + RzBinFile *bf = rz_bin_cur(core->bin); + if (!bf) { + return {}; + } + const RzList *fields = rz_bin_object_get_fields(bf->o); + if (!fields) { + return {}; + } + RzListIter *iter; + RzBinField *field; QList ret; - for (CutterJson headerObject : cmdj("ihj")) { + CutterRzListForeach (fields, iter, RzBinField, field) { HeaderDescription header; - - header.vaddr = headerObject[RJsonKey::vaddr].toRVA(); - header.paddr = headerObject[RJsonKey::paddr].toRVA(); - header.value = headerObject[RJsonKey::comment].toString(); - header.name = headerObject[RJsonKey::name].toString(); - + header.vaddr = field->vaddr; + header.paddr = field->paddr; + header.value = RZ_STR_ISEMPTY(field->comment) ? "" : field->comment; + header.name = field->name; ret << header; } @@ -3177,20 +3234,31 @@ QList CutterCore::getSignaturesDB() QList CutterCore::getAllComments(const QString &filterType) { CORE_LOCK(); - QList ret; - - for (CutterJson commentObject : cmdj("CClj")) { - QString type = commentObject[RJsonKey::type].toString(); - if (type != filterType) + QList qList; + RzIntervalTreeIter it; + void *pVoid; + RzAnalysisMetaItem *item; + RzSpace *spaces = rz_spaces_current(&core->analysis->meta_spaces); + rz_interval_tree_foreach(&core->analysis->meta, it, pVoid) + { + item = reinterpret_cast(pVoid); + if (item->type != RZ_META_TYPE_COMMENT) { continue; + } + if (spaces && spaces != item->space) { + continue; + } + if (filterType != rz_meta_type_to_string(item->type)) { + continue; + } + RzIntervalNode *node = rz_interval_tree_iter_get(&it); CommentDescription comment; - comment.offset = commentObject[RJsonKey::offset].toRVA(); - comment.name = commentObject[RJsonKey::name].toString(); - - ret << comment; + comment.offset = node->start; + comment.name = fromOwnedCharPtr(rz_str_escape(item->str)); + qList << comment; } - return ret; + return qList; } QList CutterCore::getAllRelocs() @@ -3354,82 +3422,109 @@ QStringList CutterCore::getSectionList() return ret; } +static inline QString perms_str(int perms) +{ + return QString((perms & RZ_PERM_SHAR) ? 's' : '-') + rz_str_rwx_i(perms); +} + QList CutterCore::getAllSegments() { CORE_LOCK(); - QList ret; - - for (CutterJson segmentObject : cmdj("iSSj")) { - QString name = segmentObject[RJsonKey::name].toString(); - if (name.isEmpty()) - continue; - - SegmentDescription segment; - segment.name = name; - segment.vaddr = segmentObject[RJsonKey::vaddr].toRVA(); - segment.paddr = segmentObject[RJsonKey::paddr].toRVA(); - segment.size = segmentObject[RJsonKey::size].toRVA(); - segment.vsize = segmentObject[RJsonKey::vsize].toRVA(); - segment.perm = segmentObject[RJsonKey::perm].toString(); - - ret << segment; + RzBinFile *bf = rz_bin_cur(core->bin); + if (!bf) { + return {}; } + RzList *segments = rz_bin_object_get_segments(bf->o); + if (!segments) { + return {}; + } + + RzBinSection *segment; + RzListIter *iter; + QList ret; + CutterRzListForeach (segments, iter, RzBinSection, segment) { + SegmentDescription segDesc; + segDesc.name = segment->name; + segDesc.vaddr = segment->vaddr; + segDesc.paddr = segment->paddr; + segDesc.size = segment->size; + segDesc.vsize = segment->vsize; + segDesc.perm = perms_str(segment->perm); + } + rz_list_free(segments); + return ret; } QList CutterCore::getAllEntrypoint() { CORE_LOCK(); - QList ret; + RzBinFile *bf = rz_bin_cur(core->bin); + bool va = core->io->va || core->bin->is_debugger; + ut64 baddr = rz_bin_get_baddr(core->bin); + ut64 laddr = rz_bin_get_laddr(core->bin); - for (CutterJson entrypointObject : cmdj("iej")) { - EntrypointDescription entrypoint; + QList qList; + const RzList *entries = rz_bin_object_get_entries(bf->o); + RzListIter *iter; + RzBinAddr *entry; + CutterRzListForeach (entries, iter, RzBinAddr, entry) { + if (entry->type != RZ_BIN_ENTRY_TYPE_PROGRAM) { + continue; + } + const char *type = rz_bin_entry_type_string(entry->type); - entrypoint.vaddr = entrypointObject[RJsonKey::vaddr].toRVA(); - entrypoint.paddr = entrypointObject[RJsonKey::paddr].toRVA(); - entrypoint.baddr = entrypointObject[RJsonKey::baddr].toRVA(); - entrypoint.laddr = entrypointObject[RJsonKey::laddr].toRVA(); - entrypoint.haddr = entrypointObject[RJsonKey::haddr].toRVA(); - entrypoint.type = entrypointObject[RJsonKey::type].toString(); - - ret << entrypoint; + EntrypointDescription entrypointDescription; + entrypointDescription.vaddr = rva(bf->o, entry->paddr, entry->vaddr, va); + entrypointDescription.paddr = entry->paddr; + entrypointDescription.baddr = baddr; + entrypointDescription.laddr = laddr; + entrypointDescription.haddr = entry->hpaddr ? entry->hpaddr : UT64_MAX; + entrypointDescription.type = type ? type : "unknown"; + qList << entrypointDescription; } - return ret; + + return qList; } QList CutterCore::getAllClassesFromBin() { CORE_LOCK(); - QList ret; - - for (CutterJson classObject : cmdj("icj")) { - BinClassDescription cls; - - cls.name = classObject[RJsonKey::classname].toString(); - cls.addr = classObject[RJsonKey::addr].toRVA(); - cls.index = classObject[RJsonKey::index].toUt64(); - - for (CutterJson methObject : classObject[RJsonKey::methods]) { - BinClassMethodDescription meth; - - meth.name = methObject[RJsonKey::name].toString(); - meth.addr = methObject[RJsonKey::addr].toRVA(); - - cls.methods << meth; - } - - for (CutterJson fieldObject : classObject[RJsonKey::fields]) { - BinClassFieldDescription field; - - field.name = fieldObject[RJsonKey::name].toString(); - field.addr = fieldObject[RJsonKey::addr].toRVA(); - - cls.fields << field; - } - - ret << cls; + RzBinFile *bf = rz_bin_cur(core->bin); + if (!bf) { + return {}; } - return ret; + + const RzList *cs = rz_bin_object_get_classes(bf->o); + if (!cs) { + return {}; + } + + QList qList; + RzListIter *iter, *iter2, *iter3; + RzBinClass *c; + RzBinSymbol *sym; + RzBinField *f; + CutterRzListForeach (cs, iter, RzBinClass, c) { + BinClassDescription classDescription; + classDescription.name = c->name; + classDescription.addr = c->addr; + classDescription.index = c->index; + CutterRzListForeach (c->methods, iter2, RzBinSymbol, sym) { + BinClassMethodDescription methodDescription; + methodDescription.name = sym->name; + methodDescription.addr = sym->vaddr; + classDescription.methods << methodDescription; + } + CutterRzListForeach (c->fields, iter3, RzBinField, f) { + BinClassFieldDescription fieldDescription; + fieldDescription.name = f->name; + fieldDescription.addr = f->vaddr; + classDescription.fields << fieldDescription; + } + qList << classDescription; + } + return qList; } QList CutterCore::getAllClassesFromFlags() diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 09a5d767..45cde76d 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -568,7 +568,7 @@ public: RVA getOffsetJump(RVA addr); CutterJson getFileInfo(); - CutterJson getSignatureInfo(); + QString getSignatureInfo(); CutterJson getFileVersionInfo(); void setGraphEmpty(bool empty); bool isGraphEmpty(); diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index 9b26927f..0d491009 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -153,7 +153,7 @@ void Dashboard::updateContents() ui->verticalLayout_2->addSpacerItem(spacer); // Check if signature info and version info available - if (!Core()->getSignatureInfo().size()) { + if (Core()->getSignatureInfo().isEmpty()) { ui->certificateButton->setEnabled(false); } if (!Core()->getFileVersionInfo().size()) { @@ -171,7 +171,7 @@ void Dashboard::on_certificateButton_clicked() viewDialog = new QDialog(this); view = new CutterTreeView(viewDialog); model = new JsonModel(); - qstrCertificates = Core()->getSignatureInfo().toJson(); + qstrCertificates = Core()->getSignatureInfo(); } if (!viewDialog->isVisible()) { std::string strCertificates = qstrCertificates.toUtf8().constData(); From b66c3f6f30c00c799d4e26bedb76aa9918118ab6 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Wed, 8 Jun 2022 18:34:03 +0200 Subject: [PATCH 123/240] Bump version to 2.1.0 from stable (#2962) --- .appveyor.yml | 2 +- CMakeLists.txt | 4 ++-- docs/source/conf.py | 4 ++-- rizin | 2 +- src/re.rizin.cutter.appdata.xml | 1 + 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 4f0866ae..84a3b615 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -version: '2.0.5-git-{build}' +version: '2.1.0-git-{build}' image: 'Visual Studio 2017' clone_depth: 1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 034478ca..9b9a9828 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,8 +36,8 @@ if(NOT CUTTER_ENABLE_PYTHON) endif() set(CUTTER_VERSION_MAJOR 2) -set(CUTTER_VERSION_MINOR 0) -set(CUTTER_VERSION_PATCH 5) +set(CUTTER_VERSION_MINOR 1) +set(CUTTER_VERSION_PATCH 0) set(CUTTER_VERSION_FULL "${CUTTER_VERSION_MAJOR}.${CUTTER_VERSION_MINOR}.${CUTTER_VERSION_PATCH}") diff --git a/docs/source/conf.py b/docs/source/conf.py index ba34c0fb..b2677d68 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -24,9 +24,9 @@ copyright = '2020, The Cutter Developers' author = 'The Cutter Developers' # The short X.Y version -version = '2.0' +version = '2.1' # The full version, including a2lpha/beta/rc tags -release = '2.0.5' +release = '2.1.0' # -- General configuration --------------------------------------------------- diff --git a/rizin b/rizin index 1a0ce1fa..6498ee67 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 1a0ce1faa3b552c4f1756d377ffa5973a9a358bf +Subproject commit 6498ee6760d37f6abb11784aa550aecd2e03100b diff --git a/src/re.rizin.cutter.appdata.xml b/src/re.rizin.cutter.appdata.xml index a622e5cd..c28c481c 100644 --- a/src/re.rizin.cutter.appdata.xml +++ b/src/re.rizin.cutter.appdata.xml @@ -25,6 +25,7 @@ xarkes + From aa222b53dfd17e6d86196fbd914b9903f4d65223 Mon Sep 17 00:00:00 2001 From: billow Date: Fri, 10 Jun 2022 19:05:25 +0800 Subject: [PATCH 124/240] Convert more commands to rizin APIs (#2964) `fdj?`, `iRj`, `om.`, `psx`, `p8`, `fj` --- src/core/Cutter.cpp | 115 +++++++++++++++++---------------- src/core/Cutter.h | 4 +- src/widgets/CommentsWidget.cpp | 6 +- src/widgets/HexWidget.cpp | 14 ++-- 4 files changed, 68 insertions(+), 71 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 80e41699..59306d39 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -845,15 +845,19 @@ void CutterCore::removeString(RVA addr) QString CutterCore::getString(RVA addr) { CORE_LOCK(); - char *s = (char *)returnAtSeek( - [&]() { - RzStrStringifyOpt opt = { 0 }; - opt.buffer = core->block; - opt.length = core->blocksize; - opt.encoding = rz_str_guess_encoding_from_buffer(core->block, core->blocksize); - return rz_str_stringify_raw_buffer(&opt, NULL); - }, - addr); + return getString(addr, core->blocksize, + rz_str_guess_encoding_from_buffer(core->block, core->blocksize)); +} + +QString CutterCore::getString(RVA addr, uint64_t len, RzStrEnc encoding, bool escape_nl) +{ + CORE_LOCK(); + RzStrStringifyOpt opt = {}; + opt.buffer = core->block; + opt.length = len; + opt.encoding = encoding; + opt.escape_nl = escape_nl; + char *s = (char *)returnAtSeek([&]() { return rz_str_stringify_raw_buffer(&opt, NULL); }, addr); return fromOwnedCharPtr(s); } @@ -1023,9 +1027,7 @@ void CutterCore::updateSeek() RVA CutterCore::prevOpAddr(RVA startAddr, int count) { CORE_LOCK(); - bool ok; - RVA offset = cmdRawAt(QString("/O %1").arg(count), startAddr).toULongLong(&ok, 16); - return ok ? offset : startAddr - count; + return rz_core_prevop_addr_force(core, startAddr, count); } RVA CutterCore::nextOpAddr(RVA startAddr, int count) @@ -1322,17 +1324,14 @@ RVA CutterCore::getLastFunctionInstruction(RVA addr) return lastBB ? rz_analysis_block_get_op_addr(lastBB, lastBB->ninstr - 1) : RVA_INVALID; } -QString CutterCore::cmdFunctionAt(QString addr) +QString CutterCore::flagAt(RVA addr) { - QString ret; - // Use cmd because cmdRaw would not work with grep - ret = cmd(QString("fd @ %1~[0]").arg(addr)); - return ret.trimmed(); -} - -QString CutterCore::cmdFunctionAt(RVA addr) -{ - return cmdFunctionAt(QString::number(addr)); + CORE_LOCK(); + RzFlagItem *f = rz_flag_get_at(core->flags, addr, true); + if (!f) { + return {}; + } + return core->flags->realnames && f->realname ? f->realname : f->name; } void CutterCore::cmdEsil(const char *command) @@ -2035,7 +2034,7 @@ void CutterCore::attachRemote(const QString &uri) [&](RzCore *core) { setConfig("cfg.debug", true); rz_core_file_reopen_remote_debug(core, uri.toStdString().c_str(), 0); - return (void *)NULL; + return nullptr; }, debugTask)) { return; @@ -2043,9 +2042,7 @@ void CutterCore::attachRemote(const QString &uri) emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this, uri]() { - if (debugTaskDialog) { - delete debugTaskDialog; - } + delete debugTaskDialog; debugTask.clear(); // Check if we actually connected bool connected = false; @@ -3536,10 +3533,8 @@ QList CutterCore::getAllClassesFromFlags() QList ret; QMap classesCache; - for (const CutterJson flagObject : cmdj("fj@F:classes")) { - QString flagName = flagObject[RJsonKey::name].toString(); - - QRegularExpressionMatch match = classFlagRegExp.match(flagName); + for (const auto &item : getAllFlags("classes")) { + QRegularExpressionMatch match = classFlagRegExp.match(item.name); if (match.hasMatch()) { QString className = match.captured(1); BinClassDescription *desc = nullptr; @@ -3553,12 +3548,12 @@ QList CutterCore::getAllClassesFromFlags() desc = it.value(); } desc->name = match.captured(1); - desc->addr = flagObject[RJsonKey::offset].toRVA(); + desc->addr = item.offset; desc->index = RVA_INVALID; continue; } - match = methodFlagRegExp.match(flagName); + match = methodFlagRegExp.match(item.name); if (match.hasMatch()) { QString className = match.captured(1); BinClassDescription *classDesc = nullptr; @@ -3578,7 +3573,7 @@ QList CutterCore::getAllClassesFromFlags() BinClassMethodDescription meth; meth.name = match.captured(2); - meth.addr = flagObject[RJsonKey::offset].toRVA(); + meth.addr = item.offset; classDesc->methods << meth; continue; } @@ -3745,21 +3740,27 @@ void CutterCore::renameAnalysisMethod(const QString &className, const QString &o QList CutterCore::getAllResources() { CORE_LOCK(); - QList resources; - - for (CutterJson resourceObject : cmdj("iRj")) { - ResourcesDescription res; - - res.name = resourceObject[RJsonKey::name].toString(); - res.vaddr = resourceObject[RJsonKey::vaddr].toRVA(); - res.index = resourceObject[RJsonKey::index].toUt64(); - res.type = resourceObject[RJsonKey::type].toString(); - res.size = resourceObject[RJsonKey::size].toUt64(); - res.lang = resourceObject[RJsonKey::lang].toString(); - - resources << res; + RzBinFile *bf = rz_bin_cur(core->bin); + if (!bf) { + return {}; } - return resources; + const RzList *resources = rz_bin_object_get_resources(bf->o); + QList resourcesDescriptions; + + RzBinResource *r; + RzListIter *it; + CutterRzListForeach (resources, it, RzBinResource, r) { + ResourcesDescription description; + description.name = r->name; + description.vaddr = r->vaddr; + description.index = r->index; + description.type = r->type; + description.size = r->size; + description.lang = r->language; + resourcesDescriptions << description; + } + + return resourcesDescriptions; } QList CutterCore::getAllVTables() @@ -3867,8 +3868,8 @@ QString CutterCore::getTypeAsC(QString name) bool CutterCore::isAddressMapped(RVA addr) { - // If value returned by "om. @ addr" is empty means that address is not mapped - return !Core()->cmdRawAt(QString("om."), addr).isEmpty(); + CORE_LOCK(); + return rz_io_map_get(core->io, addr); } QList CutterCore::getAllSearch(QString searchFor, QString space, QString in) @@ -3966,7 +3967,7 @@ QList CutterCore::getXRefs(RVA addr, bool to, bool whole_functi } xd.from_str = RzAddressString(xd.from); - xd.to_str = Core()->cmdRaw(QString("fd %1").arg(xd.to)).trimmed(); + xd.to_str = Core()->flagAt(xd.to); xrefList << xd; } @@ -3997,13 +3998,15 @@ QString CutterCore::listFlagsAsStringAt(RVA addr) QString CutterCore::nearestFlag(RVA offset, RVA *flagOffsetOut) { - auto r = cmdj(QString("fdj @ ") + QString::number(offset)); - QString name = r["name"].toString(); - if (flagOffsetOut) { - auto offsetValue = r["offset"]; - *flagOffsetOut = offsetValue.valid() ? offsetValue.toRVA() : offset; + CORE_LOCK(); + auto r = rz_flag_get_at(core->flags, offset, true); + if (!r) { + return {}; } - return name; + if (flagOffsetOut) { + *flagOffsetOut = r->offset; + } + return r->name; } void CutterCore::handleREvent(int type, void *data) diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 45cde76d..607fb7b2 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -237,8 +237,7 @@ public: RVA getFunctionStart(RVA addr); RVA getFunctionEnd(RVA addr); RVA getLastFunctionInstruction(RVA addr); - QString cmdFunctionAt(QString addr); - QString cmdFunctionAt(RVA addr); + QString flagAt(RVA addr); void createFunctionAt(RVA addr); void createFunctionAt(RVA addr, QString name); QStringList getDisassemblyPreview(RVA address, int num_of_lines); @@ -297,6 +296,7 @@ public: * @return string at requested address */ QString getString(RVA addr); + QString getString(RVA addr, uint64_t len, RzStrEnc encoding, bool escape_nl = false); void setToData(RVA addr, int size, int repeat = 1); int sizeofDataMeta(RVA addr); diff --git a/src/widgets/CommentsWidget.cpp b/src/widgets/CommentsWidget.cpp index ddb4bbb9..cf7bea12 100644 --- a/src/widgets/CommentsWidget.cpp +++ b/src/widgets/CommentsWidget.cpp @@ -128,7 +128,7 @@ QVariant CommentsModel::data(const QModelIndex &index, int role) const case CommentsModel::OffsetColumn: return RzAddressString(comment.offset); case CommentsModel::FunctionColumn: - return Core()->cmdFunctionAt(comment.offset); + return Core()->flagAt(comment.offset); case CommentsModel::CommentColumn: return comment.name; default: @@ -220,8 +220,8 @@ bool CommentsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &ri case CommentsModel::OffsetColumn: return leftComment.offset < rightComment.offset; case CommentsModel::FunctionColumn: - return Core()->cmdFunctionAt(leftComment.offset) - < Core()->cmdFunctionAt(rightComment.offset); + return Core()->flagAt(leftComment.offset) + < Core()->flagAt(rightComment.offset); case CommentsModel::CommentColumn: return leftComment.name < rightComment.name; default: diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index 76cc586a..39f63186 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -692,16 +692,10 @@ void HexWidget::copy() if (selection.isEmpty() || selection.size() > MAX_COPY_SIZE) return; - QClipboard *clipboard = QApplication::clipboard(); - if (cursorOnAscii) { - clipboard->setText( - Core()->cmdRawAt(QString("psx %1").arg(selection.size()), selection.start()) - .trimmed()); - } else { - clipboard->setText(Core()->cmdRawAt(QString("p8 %1").arg(selection.size()), - selection.start()) - .trimmed()); // TODO: copy in the format shown - } + auto x = cursorOnAscii + ? Core()->getString(selection.start(), selection.size(), RZ_STRING_ENC_8BIT, true) + : Core()->ioRead(selection.start(), (int)selection.size()).toHex(); + QApplication::clipboard()->setText(x); } void HexWidget::copyAddress() From 06c8f15ce08e5d9d4da02bdf6260aef24bd4a0a8 Mon Sep 17 00:00:00 2001 From: billow Date: Thu, 16 Jun 2022 07:28:43 +0800 Subject: [PATCH 125/240] Convert Rizin command calls to the API (#2968) * `es` * `il` * `wcr` * `.ar-` * `aets-` * `drp` * `ahts` * `e =?` * `fo` --- src/common/Decompiler.cpp | 2 +- src/core/Cutter.cpp | 55 +++++++++++++- src/core/Cutter.h | 2 + src/core/CutterCommon.h | 77 ++++++++++++++++++-- src/core/MainWindow.cpp | 6 +- src/dialogs/InitialOptionsDialog.cpp | 2 +- src/dialogs/preferences/AsmOptionsWidget.cpp | 2 +- src/menus/DisassemblyContextMenu.cpp | 18 +++-- src/widgets/CommentsWidget.cpp | 3 +- src/widgets/Dashboard.cpp | 21 +++--- 10 files changed, 151 insertions(+), 37 deletions(-) diff --git a/src/common/Decompiler.cpp b/src/common/Decompiler.cpp index 7653f1d2..1868e4e4 100644 --- a/src/common/Decompiler.cpp +++ b/src/common/Decompiler.cpp @@ -92,7 +92,7 @@ JSDecDecompiler::JSDecDecompiler(QObject *parent) : Decompiler("jsdec", "jsdec", bool JSDecDecompiler::isAvailable() { - return Core()->cmdList("es").contains("jsdec"); + return Core()->getConfigVariableSpaces().contains("jsdec"); } void JSDecDecompiler::decompileAt(RVA addr) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 59306d39..acd1e679 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1199,7 +1199,21 @@ void CutterCore::message(const QString &msg, bool debug) QString CutterCore::getConfig(const char *k) { CORE_LOCK(); - return QString(rz_config_get(core->config, k)); + return { rz_config_get(core->config, k) }; +} + +QStringList CutterCore::getConfigOptions(const char *k) +{ + CORE_LOCK(); + RzConfigNode *node = rz_config_node_get(core->config, k); + if (!(node && node->options)) { + return {}; + } + QStringList list; + for (const auto &s : CutterRzList(node->options)) { + list << s; + } + return list; } void CutterCore::setConfig(const char *k, const QVariant &v) @@ -2146,11 +2160,15 @@ void CutterCore::stopDebug() currentlyRemoteDebugging = false; emit debugTaskStateChanged(); + CORE_LOCK(); if (currentlyEmulating) { - cmdEsil("aeim-; aei-; wcr; .ar-; aets-"); + cmdEsil("aeim- ; aei-"); + resetWriteCache(); + rz_core_debug_clear_register_flags(core); + rz_core_analysis_esil_trace_stop(core); currentlyEmulating = false; } else { - rz_core_debug_process_close(core()); + rz_core_debug_process_close(core); currentlyAttachedToPID = -1; } @@ -2870,8 +2888,17 @@ bool CutterCore::isGraphEmpty() void CutterCore::getOpcodes() { + CORE_LOCK(); this->opcodes = cmdList("?O"); - this->regs = cmdList("drp~[1]"); + + this->regs = {}; + const RzList *rs = rz_reg_get_list(core->dbg->reg, RZ_REG_TYPE_ANY); + if (!rs) { + return; + } + for (const auto &r : CutterRzList(rs)) { + this->regs.push_back(r->name); + } } void CutterCore::setSettings() @@ -4430,3 +4457,23 @@ QByteArray CutterCore::ioRead(RVA addr, int len) return array; } + +QStringList CutterCore::getConfigVariableSpaces(const QString &key) +{ + CORE_LOCK(); + QStringList stringList; + for (const auto &node : CutterRzList(core->config->nodes)) { + stringList.push_back(node->name); + } + + if (!key.isEmpty()) { + stringList = stringList.filter(QRegularExpression(QString("^%0\\..*").arg(key))); + std::transform(stringList.begin(), stringList.end(), stringList.begin(), + [](const QString &x) { return x.split('.').last(); }); + } else { + std::transform(stringList.begin(), stringList.end(), stringList.begin(), + [](const QString &x) { return x.split('.').first(); }); + } + stringList.removeDuplicates(); + return stringList; +} diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 607fb7b2..9552fd82 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -393,10 +393,12 @@ public: QString getConfig(const char *k); QString getConfig(const QString &k) { return getConfig(k.toUtf8().constData()); } QString getConfigDescription(const char *k); + QStringList getConfigOptions(const char *k); QStringList getColorThemes(); QHash getTheme(); QStringList getThemeKeys(); bool setColor(const QString &key, const QString &color); + QStringList getConfigVariableSpaces(const QString &key = ""); /* Assembly\Hexdump related methods */ QByteArray assemble(const QString &code); diff --git a/src/core/CutterCommon.h b/src/core/CutterCommon.h index 6d6f7e7a..4adbf234 100644 --- a/src/core/CutterCommon.h +++ b/src/core/CutterCommon.h @@ -15,20 +15,21 @@ #endif // Q_OS_WIN // Rizin list iteration macros -#define CutterRzListForeach(list, it, type, x) \ +#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) \ +#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 +template +class CutterPVector { private: - const RzPVector * const vec; + const RzPVector *const vec; public: class iterator : public std::iterator @@ -39,10 +40,19 @@ public: 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;} + 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; } }; @@ -51,6 +61,57 @@ public: 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 6e796a8c..e599809e 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -641,7 +641,11 @@ void MainWindow::finalizeOpen() core->updateSeek(); refreshAll(); // Add fortune message - core->message("\n" + core->cmdRaw("fo")); + char *fortune = rz_core_fortune_get_random(core->core()); + if (fortune) { + core->message("\n" + QString(fortune)); + free(fortune); + } // hide all docks before showing window to avoid false positive for refreshDeferrer for (auto dockWidget : dockWidgets) { diff --git a/src/dialogs/InitialOptionsDialog.cpp b/src/dialogs/InitialOptionsDialog.cpp index 437e290f..94e43f89 100644 --- a/src/dialogs/InitialOptionsDialog.cpp +++ b/src/dialogs/InitialOptionsDialog.cpp @@ -40,7 +40,7 @@ InitialOptionsDialog::InitialOptionsDialog(MainWindow *main) updateCPUComboBox(); // os combo box - for (const auto &plugin : core->cmdList("e asm.os=?")) { + for (const auto &plugin : Core()->getConfigOptions("asm.os")) { ui->kernelComboBox->addItem(plugin, plugin); } diff --git a/src/dialogs/preferences/AsmOptionsWidget.cpp b/src/dialogs/preferences/AsmOptionsWidget.cpp index 08abec50..dd5cb7a0 100644 --- a/src/dialogs/preferences/AsmOptionsWidget.cpp +++ b/src/dialogs/preferences/AsmOptionsWidget.cpp @@ -16,7 +16,7 @@ AsmOptionsWidget::AsmOptionsWidget(PreferencesDialog *dialog) ui->setupUi(this); ui->syntaxComboBox->blockSignals(true); - for (const auto &syntax : Core()->cmdList("e asm.syntax=?")) + for (const auto &syntax : Core()->getConfigOptions("asm.syntax")) ui->syntaxComboBox->addItem(syntax, syntax); ui->syntaxComboBox->blockSignals(false); diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index c0791493..873907d2 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -524,15 +524,19 @@ void DisassemblyContextMenu::aboutToShowSlot() structureOffsetMenu->menuAction()->setVisible(true); structureOffsetMenu->clear(); - // Get the possible offsets using the "ahts" command - // TODO: add ahtj command to Rizin and then use it here - QStringList ret = Core()->cmdList("ahts " + QString::number(memDisp)); - for (const QString &val : ret) { - if (val.isEmpty()) { - continue; + RzCoreLocked core(Core()); + RzList *typeoffs = rz_type_db_get_by_offset(core->analysis->typedb, memDisp); + if (typeoffs) { + for (const auto &ty : CutterRzList(typeoffs)) { + if (RZ_STR_ISEMPTY(ty->path)) { + continue; + } + structureOffsetMenu->addAction("[" + memBaseReg + " + " + ty->path + "]") + ->setData(ty->path); } - structureOffsetMenu->addAction("[" + memBaseReg + " + " + val + "]")->setData(val); + rz_list_free(typeoffs); } + if (structureOffsetMenu->isEmpty()) { // No possible offset was found so hide the menu structureOffsetMenu->menuAction()->setVisible(false); diff --git a/src/widgets/CommentsWidget.cpp b/src/widgets/CommentsWidget.cpp index cf7bea12..065548a3 100644 --- a/src/widgets/CommentsWidget.cpp +++ b/src/widgets/CommentsWidget.cpp @@ -220,8 +220,7 @@ bool CommentsProxyModel::lessThan(const QModelIndex &left, const QModelIndex &ri case CommentsModel::OffsetColumn: return leftComment.offset < rightComment.offset; case CommentsModel::FunctionColumn: - return Core()->flagAt(leftComment.offset) - < Core()->flagAt(rightComment.offset); + return Core()->flagAt(leftComment.offset) < Core()->flagAt(rightComment.offset); case CommentsModel::CommentColumn: return leftComment.name < rightComment.name; default: diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index 0d491009..7c37c26a 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -122,12 +122,6 @@ void Dashboard::updateContents() setPlainText(ui->codeSizeLineEdit, QString::number(analinfo["codesz"].toSt64()) + " bytes"); setPlainText(ui->percentageLineEdit, QString::number(analinfo["percent"].toSt64()) + "%"); - QStringList libs = Core()->cmdList("il"); - if (!libs.isEmpty()) { - libs.removeFirst(); - libs.removeLast(); - } - // dunno: why not label->setText(lines.join("\n")? while (ui->verticalLayout_2->count() > 0) { QLayoutItem *item = ui->verticalLayout_2->takeAt(0); @@ -141,12 +135,15 @@ void Dashboard::updateContents() } } - for (const QString &lib : libs) { - QLabel *label = new QLabel(this); - label->setText(lib); - label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - label->setTextInteractionFlags(Qt::TextSelectableByMouse); - ui->verticalLayout_2->addWidget(label); + const RzList *libs = rz_bin_object_get_libs(bf->o); + if (libs) { + for (const auto &lib : CutterRzList(libs)) { + auto *label = new QLabel(this); + label->setText(lib); + label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + label->setTextInteractionFlags(Qt::TextSelectableByMouse); + ui->verticalLayout_2->addWidget(label); + } } QSpacerItem *spacer = new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding); From cb26142398ebcd14e075161469c4f859608a75ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Wed, 22 Jun 2022 20:26:54 +0200 Subject: [PATCH 126/240] Fix many null derefs when opening no file --- src/core/Cutter.cpp | 39 +++++++++++++++++++++++++-------------- src/widgets/Dashboard.cpp | 10 +++++----- 2 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index acd1e679..fc9ad1bd 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -644,6 +644,10 @@ bool CutterCore::loadFile(QString path, ut64 baddr, ut64 mapaddr, int perms, int bool CutterCore::tryFile(QString path, bool rw) { + if (path.isEmpty()) { + // opening no file is always possible + return true; + } CORE_LOCK(); RzCoreFile *cf; int flags = RZ_PERM_R; @@ -3484,6 +3488,9 @@ QList CutterCore::getAllEntrypoint() { CORE_LOCK(); RzBinFile *bf = rz_bin_cur(core->bin); + if (!bf) { + return {}; + } bool va = core->io->va || core->bin->is_debugger; ut64 baddr = rz_bin_get_baddr(core->bin); ut64 laddr = rz_bin_get_laddr(core->bin); @@ -4321,14 +4328,15 @@ void CutterCore::commitWriteCache() // Temporarily disable cache mode TempConfig tempConfig; tempConfig.set("io.cache", false); - if (!isWriteModeEnabled()) { - rz_core_io_file_reopen(core, core->io->desc->fd, RZ_PERM_RW); - rz_io_cache_commit(core->io, 0, UT64_MAX); - rz_core_block_read(core); - rz_core_io_file_open(core, core->io->desc->fd); - } else { - rz_io_cache_commit(core->io, 0, UT64_MAX); - rz_core_block_read(core); + auto desc = core->io->desc; + bool reopen = !isWriteModeEnabled() && desc; + if (reopen) { + rz_core_io_file_reopen(core, desc->fd, RZ_PERM_RW); + } + rz_io_cache_commit(core->io, 0, UT64_MAX); + rz_core_block_read(core); + if (reopen) { + rz_core_io_file_open(core, desc->fd); } } @@ -4350,13 +4358,16 @@ void CutterCore::setWriteMode(bool enabled) CORE_LOCK(); // Change from read-only to write-mode - if (enabled) { - if (!writeModeState) { - rz_core_io_file_reopen(core, core->io->desc->fd, RZ_PERM_RW); + RzIODesc *desc = core->io->desc; + if (desc) { + if (enabled) { + if (!writeModeState) { + rz_core_io_file_reopen(core, desc->fd, RZ_PERM_RW); + } + } else { + // Change from write-mode to read-only + rz_core_io_file_open(core, desc->fd); } - } else { - // Change from write-mode to read-only - rz_core_io_file_open(core, core->io->desc->fd); } // Disable cache mode because we specifically set write or // read-only modes. diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index 7c37c26a..66265d43 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -63,9 +63,9 @@ void Dashboard::updateContents() setPlainText(ui->subsysEdit, binInfo ? binInfo->subsystem : ""); setPlainText(ui->compilerEdit, binInfo ? binInfo->compiler : ""); setPlainText(ui->bitsEdit, binInfo ? QString::number(binInfo->bits) : ""); - setPlainText(ui->baddrEdit, binInfo ? RzAddressString(rz_bin_file_get_baddr(bf)) : ""); - setPlainText(ui->sizeEdit, binInfo ? qhelpers::formatBytecount(bf->size) : ""); - setPlainText(ui->fdEdit, binInfo ? QString::number(bf->fd) : ""); + setPlainText(ui->baddrEdit, bf ? RzAddressString(rz_bin_file_get_baddr(bf)) : ""); + setPlainText(ui->sizeEdit, bf ? qhelpers::formatBytecount(bf->size) : ""); + setPlainText(ui->fdEdit, bf ? QString::number(bf->fd) : ""); // Setting the value of "Endianness" const char *endian = binInfo ? (binInfo->big_endian ? "BE" : "LE") : ""; @@ -78,7 +78,7 @@ void Dashboard::updateContents() int static_value = rz_bin_is_static(core->bin); setPlainText(ui->staticEdit, tr(setBoolText(static_value))); - RzList *hashes = rz_bin_file_compute_hashes(core->bin, bf, UT64_MAX); + RzList *hashes = bf ? rz_bin_file_compute_hashes(core->bin, bf, UT64_MAX) : nullptr; // Delete hashesWidget if it isn't null to avoid duplicate components if (hashesWidget) { @@ -135,7 +135,7 @@ void Dashboard::updateContents() } } - const RzList *libs = rz_bin_object_get_libs(bf->o); + const RzList *libs = bf ? rz_bin_object_get_libs(bf->o) : nullptr; if (libs) { for (const auto &lib : CutterRzList(libs)) { auto *label = new QLabel(this); From 5b777b820203f554338f387bc05c8c42e0763ee0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Wed, 22 Jun 2022 20:36:20 +0200 Subject: [PATCH 127/240] Fix sections entropy display --- src/core/Cutter.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index fc9ad1bd..1c19fc70 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3420,7 +3420,6 @@ QList CutterCore::getAllSections() section.entropy = rz_str_get(entropy); ht_pp_free(digests); } - section.entropy = ""; sections << section; } From e60ba18e43362203ed643a2722992169fbdcef8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Wed, 22 Jun 2022 20:36:30 +0200 Subject: [PATCH 128/240] Fix segments listing --- src/core/Cutter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 1c19fc70..53e06fcf 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3477,6 +3477,7 @@ QList CutterCore::getAllSegments() segDesc.size = segment->size; segDesc.vsize = segment->vsize; segDesc.perm = perms_str(segment->perm); + ret << segDesc; } rz_list_free(segments); From f99ffc3dbde8c437f45f04d1a3e57584b712234f Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Thu, 23 Jun 2022 01:44:25 +0200 Subject: [PATCH 129/240] Fix #2958 - Add checkbox to fill remaining bytes with nops. (#2974) --- src/core/Cutter.cpp | 8 ++++++-- src/core/Cutter.h | 2 +- src/dialogs/EditInstructionDialog.cpp | 17 +++++++++++++++++ src/dialogs/EditInstructionDialog.h | 6 +++--- src/dialogs/EditInstructionDialog.ui | 24 +++++++++++++++++++++++- src/menus/DisassemblyContextMenu.cpp | 3 ++- 6 files changed, 52 insertions(+), 8 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 53e06fcf..b1996b79 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -762,10 +762,14 @@ QString CutterCore::getInstructionOpcode(RVA addr) return fromOwnedCharPtr(ret); } -void CutterCore::editInstruction(RVA addr, const QString &inst) +void CutterCore::editInstruction(RVA addr, const QString &inst, bool fillWithNops) { CORE_LOCK(); - rz_core_write_assembly(core, addr, inst.trimmed().toStdString().c_str()); + if (fillWithNops) { + rz_core_write_assembly_fill(core, addr, inst.trimmed().toStdString().c_str()); + } else { + rz_core_write_assembly(core, addr, inst.trimmed().toStdString().c_str()); + } emit instructionChanged(addr); } diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 9552fd82..4263a8a8 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -259,7 +259,7 @@ public: /* Edition functions */ QString getInstructionBytes(RVA addr); QString getInstructionOpcode(RVA addr); - void editInstruction(RVA addr, const QString &inst); + void editInstruction(RVA addr, const QString &inst, bool fillWithNops = false); void nopInstruction(RVA addr); void jmpReverse(RVA addr); void editBytes(RVA addr, const QString &inst); diff --git a/src/dialogs/EditInstructionDialog.cpp b/src/dialogs/EditInstructionDialog.cpp index d619bb51..041aea91 100644 --- a/src/dialogs/EditInstructionDialog.cpp +++ b/src/dialogs/EditInstructionDialog.cpp @@ -2,12 +2,20 @@ #include "ui_EditInstructionDialog.h" #include "core/Cutter.h" +#include + EditInstructionDialog::EditInstructionDialog(InstructionEditMode editMode, QWidget *parent) : QDialog(parent), ui(new Ui::EditInstructionDialog), editMode(editMode) { ui->setupUi(this); ui->lineEdit->setMinimumWidth(400); ui->instructionLabel->setWordWrap(true); + if (editMode == EDIT_TEXT) { + ui->fillWithNops->setVisible(true); + ui->fillWithNops->setCheckState(Qt::Checked); + } else { + ui->fillWithNops->setVisible(false); + } setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint)); connect(ui->lineEdit, &QLineEdit::textEdited, this, &EditInstructionDialog::updatePreview); @@ -22,6 +30,15 @@ void EditInstructionDialog::on_buttonBox_rejected() close(); } +bool EditInstructionDialog::needsNops() const +{ + if (editMode != EDIT_TEXT) { + return false; + } + + return ui->fillWithNops->checkState() == Qt::Checked; +} + QString EditInstructionDialog::getInstruction() const { return ui->lineEdit->text(); diff --git a/src/dialogs/EditInstructionDialog.h b/src/dialogs/EditInstructionDialog.h index f343ed7d..1235a734 100644 --- a/src/dialogs/EditInstructionDialog.h +++ b/src/dialogs/EditInstructionDialog.h @@ -20,18 +20,18 @@ public: QString getInstruction() const; void setInstruction(const QString &instruction); + bool needsNops() const; private slots: void on_buttonBox_accepted(); - void on_buttonBox_rejected(); void updatePreview(const QString &input); private: std::unique_ptr ui; - InstructionEditMode - editMode; // true if editing intruction **bytes**; false if editing instruction **text** + // defines if the user is editing bytes or asm + InstructionEditMode editMode; }; #endif // EDITINSTRUCTIONDIALOG_H diff --git a/src/dialogs/EditInstructionDialog.ui b/src/dialogs/EditInstructionDialog.ui index 6ff8661b..98d53131 100644 --- a/src/dialogs/EditInstructionDialog.ui +++ b/src/dialogs/EditInstructionDialog.ui @@ -7,7 +7,7 @@ 0 0 400 - 118 + 151 @@ -37,6 +37,18 @@ + + 5 + + + 5 + + + 5 + + + 5 + @@ -82,6 +94,16 @@ + + + + Fill all remaining bytes with NOP opcodes + + + true + + + diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 873907d2..f3f2dcfb 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -708,9 +708,10 @@ void DisassemblyContextMenu::on_actionEditInstruction_triggered() e.setInstruction(oldInstructionOpcode); if (e.exec()) { + bool fillWithNops = e.needsNops(); QString userInstructionOpcode = e.getInstruction(); if (userInstructionOpcode != oldInstructionOpcode) { - Core()->editInstruction(offset, userInstructionOpcode); + Core()->editInstruction(offset, userInstructionOpcode, fillWithNops); } } } From 8f7aebe7c72a893bec4fce47e02d608ac6b3fd65 Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Sat, 25 Jun 2022 09:51:17 +0200 Subject: [PATCH 130/240] CutterCore: select the right RzReg based on debug/emulation status (#2977) --- src/core/Cutter.cpp | 38 ++++++++++++++++++++++++++------------ src/core/Cutter.h | 4 ++++ 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index b1996b79..abb86e4b 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -129,7 +129,10 @@ static QString fromOwnedCharPtr(char *str) static bool reg_sync(RzCore *core, RzRegisterType type, bool write) { - return rz_debug_reg_sync(core->dbg, type, write); + if (rz_core_is_debug(core)) { + return rz_debug_reg_sync(core->dbg, type, write); + } + return true; } RzCoreLocked::RzCoreLocked(CutterCore *core) : core(core) @@ -1514,6 +1517,17 @@ RefDescription CutterCore::formatRefDesc(const QSharedPointer &refItem return desc; } +RzReg *CutterCore::getReg() +{ + CORE_LOCK(); + if (currentlyDebugging && currentlyEmulating) { + return core->analysis->reg; + } else if (currentlyDebugging) { + return core->dbg->reg; + } + return core->analysis->reg; +} + QList CutterCore::getRegisterRefs(int depth) { QList ret; @@ -1522,7 +1536,7 @@ QList CutterCore::getRegisterRefs(int depth) } CORE_LOCK(); - RzList *ritems = rz_core_reg_filter_items_sync(core, core->dbg->reg, reg_sync, nullptr); + RzList *ritems = rz_core_reg_filter_items_sync(core, getReg(), reg_sync, nullptr); if (!ritems) { return ret; } @@ -1530,7 +1544,7 @@ QList CutterCore::getRegisterRefs(int depth) RzRegItem *ri; CutterRzListForeach (ritems, it, RzRegItem, ri) { RegisterRef reg; - reg.value = rz_reg_get_value(core->dbg->reg, ri); + reg.value = rz_reg_get_value(getReg(), ri); reg.ref = getAddrRefs(reg.value, depth); reg.name = ri->name; ret.append(reg); @@ -1547,7 +1561,7 @@ QList CutterCore::getStack(int size, int depth) } CORE_LOCK(); - RVA addr = rz_debug_reg_get(core->dbg, "SP"); + RVA addr = rz_core_reg_getv_by_role_or_name(core, "SP"); if (addr == RVA_INVALID) { return stack; } @@ -1596,7 +1610,7 @@ AddrRefs CutterCore::getAddrRefs(RVA addr, int depth) // Check if the address points to a register RzFlagItem *fi = rz_flag_get_i(core->flags, addr); if (fi) { - RzRegItem *r = rz_reg_get(core->dbg->reg, fi->name, -1); + RzRegItem *r = rz_reg_get(getReg(), fi->name, -1); if (r) { refs.reg = r->name; } @@ -1852,7 +1866,7 @@ QVector CutterCore::getRegisterRefValues() { QVector result; CORE_LOCK(); - RzList *ritems = rz_core_reg_filter_items_sync(core, core->dbg->reg, reg_sync, nullptr); + RzList *ritems = rz_core_reg_filter_items_sync(core, getReg(), reg_sync, nullptr); if (!ritems) { return result; } @@ -1861,8 +1875,8 @@ QVector CutterCore::getRegisterRefValues() CutterRzListForeach (ritems, it, RzRegItem, ri) { RegisterRefValueDescription desc; desc.name = ri->name; - ut64 value = rz_reg_get_value(core->dbg->reg, ri); - desc.value = QString::number(value); + ut64 value = rz_reg_get_value(getReg(), ri); + desc.value = "0x" + QString::number(value, 16); desc.ref = rz_core_analysis_hasrefs(core, value, true); result.push_back(desc); } @@ -1876,14 +1890,14 @@ QString CutterCore::getRegisterName(QString registerRole) return ""; } CORE_LOCK(); - return rz_reg_get_name_by_type(core->dbg->reg, registerRole.toUtf8().constData()); + return rz_reg_get_name_by_type(getReg(), registerRole.toUtf8().constData()); } RVA CutterCore::getProgramCounterValue() { if (currentlyDebugging) { CORE_LOCK(); - return rz_debug_reg_get(core->dbg, "PC"); + return rz_core_reg_getv_by_role_or_name(core, "PC"); } return RVA_INVALID; } @@ -1895,7 +1909,7 @@ void CutterCore::setRegister(QString regName, QString regValue) } CORE_LOCK(); ut64 val = rz_num_math(core->num, regValue.toUtf8().constData()); - rz_core_reg_assign_sync(core, core->dbg->reg, reg_sync, regName.toUtf8().constData(), val); + rz_core_reg_assign_sync(core, getReg(), reg_sync, regName.toUtf8().constData(), val); emit registersChanged(); emit refreshCodeViews(); } @@ -2900,7 +2914,7 @@ void CutterCore::getOpcodes() this->opcodes = cmdList("?O"); this->regs = {}; - const RzList *rs = rz_reg_get_list(core->dbg->reg, RZ_REG_TYPE_ANY); + const RzList *rs = rz_reg_get_list(getReg(), RZ_REG_TYPE_ANY); if (!rs) { return; } diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 4263a8a8..b5be0ff8 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -662,6 +662,10 @@ public: QList getAllSearch(QString searchFor, QString space, QString in); QList getBreakpoints(); QList getAllProcesses(); + /** + * @brief Get the right RzReg object based on the cutter state (debugging vs emulating) + */ + RzReg *getReg(); /** * @brief returns a list of reg values and their telescoped references * @param depth telescoping depth From 29bd3d0dbd1359a9cd9c75eff20716054002e2b6 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Sat, 25 Jun 2022 15:03:45 +0200 Subject: [PATCH 131/240] Add back jsdec which was wrongly removed. (#2983) --- .github/workflows/ccpp.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index a1c8e0c5..4adc9fd1 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -123,6 +123,7 @@ jobs: -DCUTTER_ENABLE_SIGDB=ON \ -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON \ -DCUTTER_PACKAGE_RZ_GHIDRA=ON \ + -DCUTTER_PACKAGE_JSDEC=ON \ -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \ -DCUTTER_PACKAGE_RZ_LIBYARA=ON \ -DCMAKE_INSTALL_PREFIX=appdir/usr \ From ddacbd78280a62b48fbacfce382cc09b0f86d8ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 25 Jun 2022 15:20:50 +0200 Subject: [PATCH 132/240] Extend blocksize to work around pdJ printing to few lines (#2984) --- src/core/Cutter.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index abb86e4b..76397be8 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -219,6 +219,11 @@ void CutterCore::initialize(bool loadPlugins) // Otherwise Rizin may ask the user for input and Cutter would freeze setConfig("scr.interactive", false); + // Temporary workaround for https://github.com/rizinorg/rizin/issues/2741 + // Otherwise sometimes disassembly is truncated. + // The blocksize here is a rather arbitrary value larger than the default 0x100. + rz_core_block_size(core, 0x400); + // Initialize graph node highlighter bbHighlighter = new BasicBlockHighlighter(); From df71da8f535b82992d2166ac918072d0ac97ed80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 1 Jul 2022 16:49:58 +0200 Subject: [PATCH 133/240] Update rizin dev (#2987) Relevant breaking commits in rizin: 9ea7c2fa5acd0b9b0c178a1b4316adc129e7c512 2987e035da827903329ec6433410899b985e2434 --- cmake/BundledRizin.cmake | 2 +- rizin | 2 +- src/core/Cutter.cpp | 2 +- src/widgets/HexdumpWidget.cpp | 12 ++++++------ 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index 7955c279..0a3c4491 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -56,7 +56,7 @@ endif() # TODO: This version number should be fetched automatically # instead of being hardcoded. -set (Rizin_VERSION 0.4) +set (Rizin_VERSION 0.5) set (RZ_LIBS rz_core rz_config rz_cons rz_io rz_util rz_flag rz_asm rz_debug rz_hash rz_bin rz_lang rz_il rz_analysis rz_parse rz_bp rz_egg rz_reg diff --git a/rizin b/rizin index 6498ee67..0fc9c968 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 6498ee6760d37f6abb11784aa550aecd2e03100b +Subproject commit 0fc9c9682e8a74245e4f24b84508f2bb6b185328 diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 76397be8..61882cfc 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -4232,7 +4232,7 @@ QString CutterCore::getVersionInformation() { "rz_crypto", &rz_crypto_version }, { "rz_bp", &rz_bp_version }, { "rz_debug", &rz_debug_version }, - { "rz_msg_digest", &rz_msg_digest_version }, + { "rz_hash", &rz_hash_version }, { "rz_io", &rz_io_version }, #if !USE_LIB_MAGIC { "rz_magic", &rz_magic_version }, diff --git a/src/widgets/HexdumpWidget.cpp b/src/widgets/HexdumpWidget.cpp index ce12be37..e6a088c4 100644 --- a/src/widgets/HexdumpWidget.cpp +++ b/src/widgets/HexdumpWidget.cpp @@ -244,24 +244,24 @@ void HexdumpWidget::updateParseWindow(RVA start_address, int size) : ""); } else { // Fill the information tab hashes and entropy - RzMsgDigestSize digest_size = 0; + RzHashSize digest_size = 0; RzCoreLocked core(Core()); ut64 old_offset = core->offset; rz_core_seek(core, start_address, true); ut8 *block = core->block; - char *digest = rz_msg_digest_calculate_small_block_string("md5", block, size, &digest_size, false); + char *digest = rz_hash_cfg_calculate_small_block_string(core->hash, "md5", block, size, &digest_size, false); ui->bytesMD5->setText(QString(digest)); free(digest); - digest = rz_msg_digest_calculate_small_block_string("sha1", block, size, &digest_size, false); + digest = rz_hash_cfg_calculate_small_block_string(core->hash, "sha1", block, size, &digest_size, false); ui->bytesSHA1->setText(QString(digest)); free(digest); - digest = rz_msg_digest_calculate_small_block_string("sha256", block, size, &digest_size, false); + digest = rz_hash_cfg_calculate_small_block_string(core->hash, "sha256", block, size, &digest_size, false); ui->bytesSHA256->setText(QString(digest)); free(digest); - digest = rz_msg_digest_calculate_small_block_string("crc32", block, size, &digest_size, false); + digest = rz_hash_cfg_calculate_small_block_string(core->hash, "crc32", block, size, &digest_size, false); ui->bytesCRC32->setText(QString(digest)); free(digest); - digest = rz_msg_digest_calculate_small_block_string("entropy", block, size, &digest_size, false); + digest = rz_hash_cfg_calculate_small_block_string(core->hash, "entropy", block, size, &digest_size, false); ui->bytesEntropy->setText(QString(digest)); free(digest); rz_core_seek(core, old_offset, true); From 91fce8220bcd8e643d119126c95a0d31c2154763 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 2 Jul 2022 14:23:13 +0200 Subject: [PATCH 134/240] Remove direct download from update check (#2989) Hardcoded prediction of filenames for future releases is too prone to break, which is what happened with v2.1.0. So better to provide the link to the release page only. --- src/common/UpdateWorker.cpp | 124 ++---------------------------------- src/common/UpdateWorker.h | 64 ++----------------- 2 files changed, 9 insertions(+), 179 deletions(-) diff --git a/src/common/UpdateWorker.cpp b/src/common/UpdateWorker.cpp index 1514bc38..065e19c2 100644 --- a/src/common/UpdateWorker.cpp +++ b/src/common/UpdateWorker.cpp @@ -52,29 +52,6 @@ void UpdateWorker::checkCurrentVersion(time_t timeoutMs) pending = true; } -void UpdateWorker::download(QString filename, QString version) -{ - downloadFile.setFileName(filename); - downloadFile.open(QIODevice::WriteOnly); - - QNetworkRequest request; -# if QT_VERSION >= QT_VERSION_CHECK(5, 6, 0) && QT_VERSION < QT_VERSION_CHECK(5, 9, 0) - request.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true); -# elif QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) - request.setAttribute(QNetworkRequest::RedirectPolicyAttribute, - QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy); -# endif - QUrl url(QString("https://github.com/rizinorg/cutter/releases/" - "download/v%1/%2") - .arg(version) - .arg(getRepositoryFileName())); - request.setUrl(url); - - downloadReply = nm.get(request); - connect(downloadReply, &QNetworkReply::downloadProgress, this, &UpdateWorker::process); - connect(downloadReply, &QNetworkReply::finished, this, &UpdateWorker::serveDownloadFinish); -} - void UpdateWorker::showUpdateDialog(bool showDontCheckForUpdatesButton) { QMessageBox mb; @@ -82,69 +59,23 @@ void UpdateWorker::showUpdateDialog(bool showDontCheckForUpdatesButton) mb.setText(tr("There is an update available for Cutter.
") + "" + tr("Current version:") + " " CUTTER_VERSION_FULL "
" + "" + tr("Latest version:") + " " + latestVersion.toString() + "

" - + tr("For update, please check the link:
") + + tr("To update, please check the link:
") + QString("" "https://github.com/rizinorg/cutter/releases/tag/v%1
") - .arg(latestVersion.toString()) - + tr("or click \"Download\" to download latest version of Cutter.")); + .arg(latestVersion.toString())); if (showDontCheckForUpdatesButton) { - mb.setStandardButtons(QMessageBox::Save | QMessageBox::Reset | QMessageBox::Ok); - mb.button(QMessageBox::Reset)->setText(tr("Don't check for updates")); + mb.setStandardButtons(QMessageBox::Reset | QMessageBox::Ok); + mb.button(QMessageBox::Reset)->setText(tr("Don't check for updates automatically")); } else { - mb.setStandardButtons(QMessageBox::Save | QMessageBox::Ok); + mb.setStandardButtons(QMessageBox::Ok); } - mb.button(QMessageBox::Save)->setText(tr("Download")); mb.setDefaultButton(QMessageBox::Ok); int ret = mb.exec(); if (ret == QMessageBox::Reset) { Config()->setAutoUpdateEnabled(false); - } else if (ret == QMessageBox::Save) { - QString fullFileName = QFileDialog::getSaveFileName( - nullptr, tr("Choose directory for downloading"), - QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + QDir::separator() - + getRepositoryFileName(), - QString("%1 (*.%1)").arg(getRepositeryExt())); - if (!fullFileName.isEmpty()) { - QProgressDialog progressDial(tr("Downloading update..."), tr("Cancel"), 0, 100); - connect(this, &UpdateWorker::downloadProcess, &progressDial, - [&progressDial](size_t curr, size_t total) { - progressDial.setValue(100.0f * curr / total); - }); - connect(&progressDial, &QProgressDialog::canceled, this, &UpdateWorker::abortDownload); - connect(this, &UpdateWorker::downloadFinished, &progressDial, &QProgressDialog::cancel); - connect(this, &UpdateWorker::downloadFinished, this, [](QString filePath) { - QMessageBox info(QMessageBox::Information, tr("Download finished!"), - tr("Latest version of Cutter was succesfully downloaded!"), - QMessageBox::Yes | QMessageBox::Open | QMessageBox::Ok, nullptr); - info.button(QMessageBox::Open)->setText(tr("Open file")); - info.button(QMessageBox::Yes)->setText(tr("Open download folder")); - int r = info.exec(); - if (r == QMessageBox::Open) { - QDesktopServices::openUrl(filePath); - } else if (r == QMessageBox::Yes) { - auto path = filePath.split('/'); - path.removeLast(); - QDesktopServices::openUrl(path.join('/')); - } - }); - download(fullFileName, latestVersion.toString()); - // Calling show() before exec() is only way make dialog non-modal - // it seems weird, but it works - progressDial.show(); - progressDial.exec(); - } } } -void UpdateWorker::abortDownload() -{ - disconnect(downloadReply, &QNetworkReply::finished, this, &UpdateWorker::serveDownloadFinish); - disconnect(downloadReply, &QNetworkReply::downloadProgress, this, &UpdateWorker::process); - downloadReply->close(); - downloadReply->deleteLater(); - downloadFile.remove(); -} - void UpdateWorker::serveVersionCheckReply() { pending = false; @@ -168,51 +99,6 @@ void UpdateWorker::serveVersionCheckReply() emit checkComplete(versionReply, errStr); } -void UpdateWorker::serveDownloadFinish() -{ - downloadReply->close(); - downloadReply->deleteLater(); - if (downloadReply->error()) { - emit downloadError(downloadReply->errorString()); - } else { - emit downloadFinished(downloadFile.fileName()); - } -} - -void UpdateWorker::process(size_t bytesReceived, size_t bytesTotal) -{ - downloadFile.write(downloadReply->readAll()); - emit downloadProcess(bytesReceived, bytesTotal); -} - -QString UpdateWorker::getRepositeryExt() const -{ -# ifdef Q_OS_LINUX - return "AppImage"; -# elif defined(Q_OS_WIN64) || defined(Q_OS_WIN32) - return "zip"; -# elif defined(Q_OS_MACOS) - return "dmg"; -# endif -} - -QString UpdateWorker::getRepositoryFileName() const -{ - QString downloadFileName; -# ifdef Q_OS_LINUX - downloadFileName = "Cutter-v%1-x%2.Linux.AppImage"; -# elif defined(Q_OS_WIN64) || defined(Q_OS_WIN32) - downloadFileName = "Cutter-v%1-x%2.Windows.zip"; -# elif defined(Q_OS_MACOS) - downloadFileName = "Cutter-v%1-x%2.macOS.dmg"; -# endif - downloadFileName = - downloadFileName.arg(latestVersion.toString()) - .arg(QSysInfo::buildAbi().split('-').at(2).contains("64") ? "64" : "32"); - - return downloadFileName; -} - QVersionNumber UpdateWorker::currentVersionNumber() { return QVersionNumber(CUTTER_VERSION_MAJOR, CUTTER_VERSION_MINOR, CUTTER_VERSION_PATCH); diff --git a/src/common/UpdateWorker.h b/src/common/UpdateWorker.h index 61b8d038..46854f87 100644 --- a/src/common/UpdateWorker.h +++ b/src/common/UpdateWorker.h @@ -23,8 +23,7 @@ class QNetworkReply; /** * @class UpdateWorker - * @brief The UpdateWorker class is a class providing API to check for current Cutter version - * and download specific version of one. + * @brief The UpdateWorker class is a class providing API to check for current Cutter version. */ class UpdateWorker : public QObject @@ -47,23 +46,12 @@ public: void checkCurrentVersion(time_t timeoutMs); - /** - * @fn void UpdateWorker::download(QDir downloadPath, QString version) - * - * @brief Downloads provided @a version of Cutter into @a downloadDir. - * - * @sa downloadProcess(size_t bytesReceived, size_t bytesTotal) - */ - void download(QString filename, QString version); - /** * @fn void UpdateWorker::showUpdateDialog() * - * Shows dialog that allows user to either download latest version of Cutter from website - * or download it by clicking on a button. This dialog also has "Don't check for updates" - * button which disables on-start update checks if @a showDontCheckForUpdatesButton is true. - * - * @sa downloadProcess(size_t bytesReceived, size_t bytesTotal) + * Shows dialog that allows user to download latest version of Cutter from website. + * This dialog also has "Don't check for updates" button which disables on-start update + * checks if @a showDontCheckForUpdatesButton is true. */ void showUpdateDialog(bool showDontCheckForUpdatesButton); @@ -73,18 +61,6 @@ public: */ static QVersionNumber currentVersionNumber(); -public slots: - /** - * @fn void UpdateWorker::abortDownload() - * - * @brief Stops current process of downloading. - * - * @note UpdateWorker::downloadFinished(QString filename) is not send after this function. - * - * @sa download(QDir downloadDir, QString version) - */ - void abortDownload(); - signals: /** * @fn UpdateWorker::checkComplete(const QString& verson, const QString& errorMsg) @@ -95,46 +71,14 @@ signals: */ void checkComplete(const QVersionNumber &currVerson, const QString &errorMsg); - /** - * @fn UpdateWorker::downloadProcess(size_t bytesReceived, size_t bytesTotal) - * - * The signal is emitted each time when some amount of bytes was downloaded. - * May be used as indicator of download progress. - */ - void downloadProcess(size_t bytesReceived, size_t bytesTotal); - - /** - * @fn UpdateWorker::downloadFinished(QString filename) - * - * @brief The signal is emitted as soon as downloading completes. - */ - void downloadFinished(QString filename); - - /** - * @fn UpdateWorker::downloadError(QString errorStr) - * - * @brief The signal is emitted when error occures during download. - */ - void downloadError(QString errorStr); - private slots: void serveVersionCheckReply(); - void serveDownloadFinish(); - - void process(size_t bytesReceived, size_t bytesTotal); - -private: - QString getRepositeryExt() const; - QString getRepositoryFileName() const; - private: QNetworkAccessManager nm; QVersionNumber latestVersion; QTimer t; bool pending; - QFile downloadFile; - QNetworkReply *downloadReply; QNetworkReply *checkReply; }; From e4db94eb87d8f74571c0deacfd46dfc9dd844f9e Mon Sep 17 00:00:00 2001 From: billow Date: Sat, 2 Jul 2022 21:49:13 +0800 Subject: [PATCH 135/240] Convert to rizin APIs (#2973) `rz_core_bin_get_compile_time`, `ij`/`CutterCore::getFileInfo()`, `aaij`, `iVj`, `iEj`, `izzj`, `iMj`, `aeim-`, `aei-`, `tc`, `rz_core_config_variable_spaces`, `o`, `oodf` --- src/common/BugReporting.cpp | 24 +-- src/core/Cutter.cpp | 144 +++++++++++------- src/core/Cutter.h | 5 +- src/dialogs/VersionInfoDialog.cpp | 242 +++++++++++++++++++----------- src/widgets/Dashboard.cpp | 64 ++++---- src/widgets/FunctionsWidget.cpp | 13 +- src/widgets/TypesWidget.cpp | 8 +- 7 files changed, 310 insertions(+), 190 deletions(-) diff --git a/src/common/BugReporting.cpp b/src/common/BugReporting.cpp index 7d5ec919..18aa36ef 100644 --- a/src/common/BugReporting.cpp +++ b/src/common/BugReporting.cpp @@ -8,26 +8,18 @@ void openIssue() { + RzCoreLocked core(Core()); + RzBinFile *bf = rz_bin_cur(core->bin); + RzBinInfo *info = rz_bin_get_info(core->bin); + RzBinPlugin *plugin = rz_bin_file_cur_plugin(bf); + QString url, osInfo, format, arch, type; // Pull in info needed for git issue osInfo = QSysInfo::productType() + " " + (QSysInfo::productVersion() == "unknown" ? "" : QSysInfo::productVersion()); - CutterJson docu = Core()->getFileInfo(); - CutterJson coreObj = docu["core"]; - CutterJson binObj = docu["bin"]; - if (binObj.size()) { - format = coreObj["format"].toString(); - arch = binObj["arch"].toString(); - if (binObj["type"].valid()) { - type = coreObj["type"].toString(); - } else { - type = "N/A"; - } - } else { - format = coreObj["format"].toString(); - arch = "N/A"; - type = "N/A"; - } + format = plugin && RZ_STR_ISNOTEMPTY(plugin->name) ? plugin->name : "N/A"; + arch = info && RZ_STR_ISNOTEMPTY(info->arch) ? info->arch : "N/A"; + type = info && RZ_STR_ISNOTEMPTY(info->type) ? info->type : "N/A"; url = "https://github.com/rizinorg/cutter/issues/new?&body=**Environment information**\n* " "Operating System: " + osInfo + "\n* Cutter version: " + CUTTER_VERSION_FULL + "\n* Obtained from:\n" diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 61882cfc..f3c0f0de 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -681,7 +681,7 @@ bool CutterCore::mapFile(QString path, RVA mapaddr) { CORE_LOCK(); RVA addr = mapaddr != RVA_INVALID ? mapaddr : 0; - ut64 baddr = Core()->getFileInfo()["bin"]["baddr"].toUt64(); + ut64 baddr = rz_bin_get_baddr(core->bin); if (rz_core_file_open(core, path.toUtf8().constData(), RZ_PERM_RX, addr)) { rz_core_bin_load(core, path.toUtf8().constData(), baddr); } else { @@ -1434,16 +1434,6 @@ bool CutterCore::registerDecompiler(Decompiler *decompiler) return true; } -CutterJson CutterCore::getFileInfo() -{ - return cmdj("ij"); -} - -CutterJson CutterCore::getFileVersionInfo() -{ - return cmdj("iVj"); -} - QString CutterCore::getSignatureInfo() { CORE_LOCK(); @@ -1456,9 +1446,23 @@ QString CutterCore::getSignatureInfo() if (!signature) { return {}; } + auto sig = parseJson(signature, nullptr); + if (sig.size() == 0) { + return {}; + } return fromOwnedCharPtr(signature); } +bool CutterCore::existsFileInfo() +{ + CORE_LOCK(); + const RzBinInfo *info = rz_bin_get_info(core->bin); + if (!(info && info->rclass)) { + return false; + } + return strncmp("pe", info->rclass, 2) == 0 || strncmp("elf", info->rclass, 3) == 0; +} + // Utility function to check if a telescoped item exists and add it with prefixes to the desc static inline const QString appendVar(QString &dst, const QString val, const QString prepend_val, const QString append_val) @@ -2133,9 +2137,15 @@ void CutterCore::attachDebug(int pid) offsetPriorDebugging = getOffset(); } - QString attach_command = currentlyOpenFile.isEmpty() ? "o" : "oodf"; - // attach to process with dbg plugin - asyncCmd("e cfg.debug=true;" + attach_command + " dbg://" + QString::number(pid), debugTask); + CORE_LOCK(); + setConfig("cfg.debug", true); + auto uri = rz_str_newf("dbg://%d", pid); + if (currentlyOpenFile.isEmpty()) { + rz_core_file_open_load(core, uri, 0, RZ_PERM_R, false); + } else { + rz_core_file_reopen_remote_debug(core, uri, 0); + } + free(uri); emit debugTaskStateChanged(); @@ -2189,7 +2199,8 @@ void CutterCore::stopDebug() CORE_LOCK(); if (currentlyEmulating) { - cmdEsil("aeim- ; aei-"); + rz_core_analysis_esil_init_mem_del(core, NULL, UT64_MAX, UT32_MAX); + rz_core_analysis_esil_deinit(core); resetWriteCache(); rz_core_debug_clear_register_flags(core); rz_core_analysis_esil_trace_stop(core); @@ -3173,21 +3184,38 @@ QList CutterCore::getAllImports() QList CutterCore::getAllExports() { CORE_LOCK(); - QList ret; - - for (CutterJson exportObject : cmdj("iEj")) { - ExportDescription exp; - - exp.vaddr = exportObject[RJsonKey::vaddr].toRVA(); - exp.paddr = exportObject[RJsonKey::paddr].toRVA(); - exp.size = exportObject[RJsonKey::size].toRVA(); - exp.type = exportObject[RJsonKey::type].toString(); - exp.name = exportObject[RJsonKey::name].toString(); - exp.flag_name = exportObject[RJsonKey::flagname].toString(); - - ret << exp; + RzBinFile *bf = rz_bin_cur(core->bin); + if (!bf) { + return {}; + } + const RzList *symbols = rz_bin_object_get_symbols(bf->o); + if (!symbols) { + return {}; } + QString lang = getConfigi("bin.demangle") ? getConfig("bin.lang") : ""; + bool va = core->io->va || core->bin->is_debugger; + + QList ret; + for (const auto &symbol : CutterRzList(symbols)) { + if (!(symbol->name && rz_core_sym_is_export(symbol))) { + continue; + } + + RzBinSymNames sn = {}; + rz_core_sym_name_init(core, &sn, symbol, lang.isEmpty() ? NULL : lang.toUtf8().constData()); + + ExportDescription exportDescription; + exportDescription.vaddr = rva(bf->o, symbol->paddr, symbol->vaddr, va); + exportDescription.paddr = symbol->paddr; + exportDescription.size = symbol->size; + exportDescription.type = symbol->type; + exportDescription.name = sn.symbolname; + exportDescription.flag_name = sn.nameflag; + ret << exportDescription; + + rz_core_sym_name_fini(&sn); + } return ret; } @@ -3343,22 +3371,37 @@ QList CutterCore::getAllRelocs() QList CutterCore::getAllStrings() { - return parseStringsJson(cmdjTask("izzj")); -} + CORE_LOCK(); + RzBinFile *bf = rz_bin_cur(core->bin); + if (!bf) { + return {}; + } + RzBinObject *obj = rz_bin_cur_object(core->bin); + if (!obj) { + return {}; + } + RzList *l = rz_core_bin_whole_strings(core, bf); + if (!l) { + return {}; + } + + int va = core->io->va || core->bin->is_debugger; + RzStrEscOptions opt = {}; + opt.show_asciidot = false; + opt.esc_bslash = true; + opt.esc_double_quotes = true; -QList CutterCore::parseStringsJson(const CutterJson &doc) -{ QList ret; + for (const auto &str : CutterRzList(l)) { + auto section = obj ? rz_bin_get_section_at(obj, str->paddr, 0) : NULL; - for (CutterJson value : doc) { StringDescription string; - - string.string = value[RJsonKey::string].toString(); - string.vaddr = value[RJsonKey::vaddr].toRVA(); - string.type = value[RJsonKey::type].toString(); - string.size = value[RJsonKey::size].toUt64(); - string.length = value[RJsonKey::length].toUt64(); - string.section = value[RJsonKey::section].toString(); + string.string = rz_str_escape_utf8_keep_printable(str->string, &opt); + string.vaddr = obj ? rva(obj, str->paddr, str->vaddr, va) : str->paddr; + string.type = str->type; + string.size = str->size; + string.length = str->length; + string.section = section ? section->name : ""; ret << string; } @@ -3917,8 +3960,7 @@ QString CutterCore::getTypeAsC(QString name) return output; } char *earg = rz_cmd_escape_arg(name.toUtf8().constData(), RZ_CMD_ESCAPE_ONE_ARG); - // TODO: use API for `tc` command once available - QString result = cmd(QString("tc %1").arg(earg)); + QString result = fromOwnedCharPtr(rz_core_types_as_c(core, earg, true)); free(earg); return result; } @@ -4495,19 +4537,15 @@ QByteArray CutterCore::ioRead(RVA addr, int len) QStringList CutterCore::getConfigVariableSpaces(const QString &key) { CORE_LOCK(); - QStringList stringList; - for (const auto &node : CutterRzList(core->config->nodes)) { - stringList.push_back(node->name); + RzList *list = rz_core_config_in_space(core, key.toUtf8().constData()); + if (!list) { + return {}; } - if (!key.isEmpty()) { - stringList = stringList.filter(QRegularExpression(QString("^%0\\..*").arg(key))); - std::transform(stringList.begin(), stringList.end(), stringList.begin(), - [](const QString &x) { return x.split('.').last(); }); - } else { - std::transform(stringList.begin(), stringList.end(), stringList.begin(), - [](const QString &x) { return x.split('.').first(); }); + QStringList stringList; + for (const auto &x : CutterRzList(list)) { + stringList << x; } - stringList.removeDuplicates(); + rz_list_free(list); return stringList; } diff --git a/src/core/Cutter.h b/src/core/Cutter.h index b5be0ff8..9aa90b18 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -569,9 +569,8 @@ public: bool registerDecompiler(Decompiler *decompiler); RVA getOffsetJump(RVA addr); - CutterJson getFileInfo(); QString getSignatureInfo(); - CutterJson getFileVersionInfo(); + bool existsFileInfo(); void setGraphEmpty(bool empty); bool isGraphEmpty(); @@ -688,8 +687,6 @@ public: QList getXRefs(RVA addr, bool to, bool whole_function, const QString &filterType = QString()); - QList parseStringsJson(const CutterJson &doc); - void handleREvent(int type, void *data); /* Signals related */ diff --git a/src/dialogs/VersionInfoDialog.cpp b/src/dialogs/VersionInfoDialog.cpp index 7e67d594..dd43f23e 100644 --- a/src/dialogs/VersionInfoDialog.cpp +++ b/src/dialogs/VersionInfoDialog.cpp @@ -23,145 +23,213 @@ VersionInfoDialog::~VersionInfoDialog() {} void VersionInfoDialog::fillVersionInfo() { - - CutterJson doc = Core()->getFileVersionInfo(); - + RzCoreLocked core(Core()); + const RzBinInfo *info = rz_bin_get_info(core->bin); + if (!info || !info->rclass) { + return; + } // Case ELF - if (doc["verneed"].valid()) { - CutterJson verneed = doc["verneed"].first(); - CutterJson versym = doc["versym"].first(); - + if (strncmp("elf", info->rclass, 3) == 0) { // Set labels ui->leftLabel->setText("Version symbols"); ui->rightLabel->setText("Version need"); - // Left tree - QTreeWidgetItem *secNameItemL = new QTreeWidgetItem(); - secNameItemL->setText(0, "Section name:"); - secNameItemL->setText(1, versym["section_name"].toString()); - ui->leftTreeWidget->addTopLevelItem(secNameItemL); + Sdb *sdb = sdb_ns_path(core->sdb, "bin/cur/info/versioninfo/versym", 0); + if (!sdb) { + return; + } + // Left tree QTreeWidgetItem *addrItemL = new QTreeWidgetItem(); addrItemL->setText(0, "Address:"); - addrItemL->setText(1, RzAddressString(versym["address"].toRVA())); + addrItemL->setText(1, RzAddressString(sdb_num_get(sdb, "addr", 0))); ui->leftTreeWidget->addTopLevelItem(addrItemL); QTreeWidgetItem *offItemL = new QTreeWidgetItem(); offItemL->setText(0, "Offset:"); - offItemL->setText(1, RzAddressString(versym["offset"].toRVA())); + offItemL->setText(1, RzAddressString(sdb_num_get(sdb, "offset", 0))); ui->leftTreeWidget->addTopLevelItem(offItemL); - QTreeWidgetItem *linkItemL = new QTreeWidgetItem(); - linkItemL->setText(0, "Link:"); - linkItemL->setText(1, QString::number(versym["link"].toRVA())); - ui->leftTreeWidget->addTopLevelItem(linkItemL); - - QTreeWidgetItem *linkNameItemL = new QTreeWidgetItem(); - linkNameItemL->setText(0, "Link section name:"); - linkNameItemL->setText(1, versym["link_section_name"].toString()); - ui->leftTreeWidget->addTopLevelItem(linkNameItemL); - QTreeWidgetItem *entriesItemL = new QTreeWidgetItem(); entriesItemL->setText(0, "Entries:"); - for (CutterJson obj : versym["entries"]) { - QTreeWidgetItem *tempItem = new QTreeWidgetItem(); - tempItem->setText(0, RzAddressString(obj["idx"].toRVA())); - tempItem->setText(1, obj["value"].toString()); - entriesItemL->addChild(tempItem); + const ut64 num_entries = sdb_num_get(sdb, "num_entries", 0); + for (size_t i = 0; i < num_entries; ++i) { + auto key = QString("entry%0").arg(i); + const char *const value = sdb_const_get(sdb, key.toStdString().c_str(), 0); + if (!value) { + continue; + } + auto item = new QTreeWidgetItem(); + item->setText(0, RzAddressString(i)); + item->setText(1, value); + entriesItemL->addChild(item); } ui->leftTreeWidget->addTopLevelItem(entriesItemL); // Adjust columns to content qhelpers::adjustColumns(ui->leftTreeWidget, 0); + sdb = sdb_ns_path(core->sdb, "bin/cur/info/versioninfo/verneed", 0); // Right tree - QTreeWidgetItem *secNameItemR = new QTreeWidgetItem(); - secNameItemR->setText(0, "Section name:"); - secNameItemR->setText(1, verneed["section_name"].toString()); - ui->rightTreeWidget->addTopLevelItem(secNameItemR); - QTreeWidgetItem *addrItemR = new QTreeWidgetItem(); addrItemR->setText(0, "Address:"); - addrItemR->setText(1, RzAddressString(verneed["address"].toRVA())); + addrItemR->setText(1, RzAddressString(sdb_num_get(sdb, "addr", 0))); ui->rightTreeWidget->addTopLevelItem(addrItemR); QTreeWidgetItem *offItemR = new QTreeWidgetItem(); offItemR->setText(0, "Offset:"); - offItemR->setText(1, RzAddressString(verneed["offset"].toRVA())); + offItemR->setText(1, RzAddressString(sdb_num_get(sdb, "offset", 0))); ui->rightTreeWidget->addTopLevelItem(offItemR); - QTreeWidgetItem *linkItemR = new QTreeWidgetItem(); - linkItemR->setText(0, "Link:"); - linkItemR->setText(1, QString::number(verneed["link"].toSt64())); - ui->rightTreeWidget->addTopLevelItem(linkItemR); - - QTreeWidgetItem *linkNameItemR = new QTreeWidgetItem(); - linkNameItemR->setText(0, "Link section name:"); - linkNameItemR->setText(1, verneed["link_section_name"].toString()); - ui->rightTreeWidget->addTopLevelItem(linkNameItemR); - QTreeWidgetItem *entriesItemR = new QTreeWidgetItem(); entriesItemR->setText(0, "Entries:"); - for (CutterJson parentObj : verneed["entries"]) { - QTreeWidgetItem *parentItem = new QTreeWidgetItem(); - QString parentString; - parentItem->setText(0, RzAddressString(parentObj["idx"].toRVA())); - parentString.append("Version: " + QString::number(parentObj["vn_version"].toSt64()) - + "\t"); - parentString.append("File: " + parentObj["file_name"].toString()); - parentItem->setText(1, parentString); + for (size_t num_version = 0;; num_version++) { + auto path_version = + QString("bin/cur/info/versioninfo/verneed/version%0").arg(num_version); + sdb = sdb_ns_path(core->sdb, path_version.toStdString().c_str(), 0); + if (!sdb) { + break; + } + const char *filename = sdb_const_get(sdb, "file_name", 0); + auto *parentItem = new QTreeWidgetItem(); + parentItem->setText(0, RzAddressString(sdb_num_get(sdb, "idx", 0))); + parentItem->setText(1, + QString("Version: %0\t" + "File: %1") + .arg(QString::number(sdb_num_get(sdb, "vn_version", 0)), + QString(filename))); - for (CutterJson childObj : parentObj["vernaux"]) { - QTreeWidgetItem *childItem = new QTreeWidgetItem(); - QString childString; - childItem->setText(0, RzAddressString(childObj["idx"].toRVA())); - childString.append("Name: " + childObj["name"].toString() + "\t"); - childString.append("Flags: " + childObj["flags"].toString() + "\t"); - childString.append("Version: " + QString::number(childObj["version"].toSt64())); + int num_vernaux = 0; + while (true) { + auto path_vernaux = + QString("%0/vernaux%1").arg(path_version, QString::number(num_vernaux++)); + sdb = sdb_ns_path(core->sdb, path_vernaux.toStdString().c_str(), 0); + if (!sdb) { + break; + } + + auto *childItem = new QTreeWidgetItem(); + childItem->setText(0, RzAddressString(sdb_num_get(sdb, "idx", 0))); + QString childString = + QString("Name: %0\t" + "Flags: %1\t" + "Version: %2\t") + .arg(sdb_const_get(sdb, "name", 0), sdb_const_get(sdb, "flags", 0), + QString::number(sdb_num_get(sdb, "version", 0))); childItem->setText(1, childString); parentItem->addChild(childItem); } entriesItemR->addChild(parentItem); } - ui->rightTreeWidget->addTopLevelItem(entriesItemR); + ui->rightTreeWidget->addTopLevelItem(entriesItemR); // Adjust columns to content qhelpers::adjustColumns(ui->rightTreeWidget, 0); - } - // Case PE - else if (doc["VS_FIXEDFILEINFO"].valid()) { - CutterJson vs = doc["VS_FIXEDFILEINFO"]; - CutterJson strings = doc["StringTable"]; - + else if (strncmp("pe", info->rclass, 2) == 0) { // Set labels ui->leftLabel->setText("VS Fixed file info"); ui->rightLabel->setText("String table"); + Sdb *sdb = NULL; // Left tree - for (CutterJson property : vs) { - QTreeWidgetItem *tempItem = new QTreeWidgetItem(); - tempItem->setText(0, property.key()); - if (property.type() == RZ_JSON_INTEGER) - tempItem->setText(1, RzHexString(property.toRVA())); - else - tempItem->setText(1, property.toString()); - ui->leftTreeWidget->addTopLevelItem(tempItem); - - // Adjust columns to content - qhelpers::adjustColumns(ui->leftTreeWidget, 0); + auto path_version = QString("bin/cur/info/vs_version_info/VS_VERSIONINFO%0").arg(0); + auto path_fixedfileinfo = QString("%0/fixed_file_info").arg(path_version); + sdb = sdb_ns_path(core->sdb, path_fixedfileinfo.toStdString().c_str(), 0); + if (!sdb) { + return; } + ut32 file_version_ms = sdb_num_get(sdb, "FileVersionMS", 0); + ut32 file_version_ls = sdb_num_get(sdb, "FileVersionLS", 0); + auto file_version = QString("%0.%1.%2.%3") + .arg(file_version_ms >> 16) + .arg(file_version_ms & 0xFFFF) + .arg(file_version_ls >> 16) + .arg(file_version_ls & 0xFFFF); + ut32 product_version_ms = sdb_num_get(sdb, "ProductVersionMS", 0); + ut32 product_version_ls = sdb_num_get(sdb, "ProductVersionLS", 0); + auto product_version = QString("%0.%1.%2.%3") + .arg(product_version_ms >> 16) + .arg(product_version_ms & 0xFFFF) + .arg(product_version_ls >> 16) + .arg(product_version_ls & 0xFFFF); + + auto item = new QTreeWidgetItem(); + item->setText(0, "Signature"); + item->setText(1, RzHexString(sdb_num_get(sdb, "Signature", 0))); + ui->leftTreeWidget->addTopLevelItem(item); + + item = new QTreeWidgetItem(); + item->setText(0, "StrucVersion"); + item->setText(1, RzHexString(sdb_num_get(sdb, "StrucVersion", 0))); + ui->leftTreeWidget->addTopLevelItem(item); + + item = new QTreeWidgetItem(); + item->setText(0, "FileVersion"); + item->setText(1, file_version); + ui->leftTreeWidget->addTopLevelItem(item); + + item = new QTreeWidgetItem(); + item->setText(0, "ProductVersion"); + item->setText(1, product_version); + ui->leftTreeWidget->addTopLevelItem(item); + + item = new QTreeWidgetItem(); + item->setText(0, "FileFlagsMask"); + item->setText(1, RzHexString(sdb_num_get(sdb, "FileFlagsMask", 0))); + ui->leftTreeWidget->addTopLevelItem(item); + + item = new QTreeWidgetItem(); + item->setText(0, "FileFlags"); + item->setText(1, RzHexString(sdb_num_get(sdb, "FileFlags", 0))); + ui->leftTreeWidget->addTopLevelItem(item); + + item = new QTreeWidgetItem(); + item->setText(0, "FileOS"); + item->setText(1, RzHexString(sdb_num_get(sdb, "FileOS", 0))); + ui->leftTreeWidget->addTopLevelItem(item); + + item = new QTreeWidgetItem(); + item->setText(0, "FileType"); + item->setText(1, RzHexString(sdb_num_get(sdb, "FileType", 0))); + ui->leftTreeWidget->addTopLevelItem(item); + + item = new QTreeWidgetItem(); + item->setText(0, "FileSubType"); + item->setText(1, RzHexString(sdb_num_get(sdb, "FileSubType", 0))); + ui->leftTreeWidget->addTopLevelItem(item); + + // Adjust columns to content + qhelpers::adjustColumns(ui->leftTreeWidget, 0); // Right tree - for (CutterJson property : strings) { - QTreeWidgetItem *tempItem = new QTreeWidgetItem(); - tempItem->setText(0, property.key()); - tempItem->setText(1, property.toString()); - ui->rightTreeWidget->addTopLevelItem(tempItem); - - // Adjust columns to content - qhelpers::adjustColumns(ui->rightTreeWidget, 0); + for (int num_stringtable = 0;; num_stringtable++) { + auto path_stringtable = QString("%0/string_file_info/stringtable%1") + .arg(path_version) + .arg(num_stringtable); + sdb = sdb_ns_path(core->sdb, path_stringtable.toStdString().c_str(), 0); + if (!sdb) { + break; + } + for (int num_string = 0; sdb; num_string++) { + auto path_string = QString("%0/string%1").arg(path_stringtable).arg(num_string); + sdb = sdb_ns_path(core->sdb, path_string.toStdString().c_str(), 0); + if (!sdb) { + continue; + } + int lenkey = 0; + int lenval = 0; + ut8 *key_utf16 = sdb_decode(sdb_const_get(sdb, "key", 0), &lenkey); + ut8 *val_utf16 = sdb_decode(sdb_const_get(sdb, "value", 0), &lenval); + item = new QTreeWidgetItem(); + item->setText(0, QString::fromUtf16(reinterpret_cast(key_utf16))); + item->setText(1, QString::fromUtf16(reinterpret_cast(val_utf16))); + ui->rightTreeWidget->addTopLevelItem(item); + free(key_utf16); + free(val_utf16); + } } + qhelpers::adjustColumns(ui->rightTreeWidget, 0); } } diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index 66265d43..3715bc36 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -32,24 +32,27 @@ Dashboard::~Dashboard() {} void Dashboard::updateContents() { - CutterJson docu = Core()->getFileInfo(); - CutterJson item = docu["core"]; - CutterJson item2 = docu["bin"]; + RzCoreLocked core(Core()); + int fd = rz_io_fd_get_current(core->io); + RzIODesc *desc = rz_io_desc_get(core->io, fd); + setPlainText(this->ui->modeEdit, desc ? rz_str_rwx_i(desc->perm & RZ_PERM_RWX) : ""); - setPlainText(this->ui->modeEdit, item["mode"].toString()); - setPlainText(this->ui->compilationDateEdit, item2["compiled"].toString()); - - if (!item2["relro"].toString().isEmpty()) { - QString relro = item2["relro"].toString().section(QLatin1Char(' '), 0, 0); - relro[0] = relro[0].toUpper(); - setPlainText(this->ui->relroEdit, relro); - } else { - setPlainText(this->ui->relroEdit, "N/A"); + RzBinFile *bf = rz_bin_cur(core->bin); + if (bf) { + setPlainText(this->ui->compilationDateEdit, rz_core_bin_get_compile_time(bf)); + if (bf->o) { + char *relco_buf = sdb_get(bf->o->kv, "elf.relro", 0); + if (RZ_STR_ISNOTEMPTY(relco_buf)) { + QString relro = QString(relco_buf).section(QLatin1Char(' '), 0, 0); + relro[0] = relro[0].toUpper(); + setPlainText(this->ui->relroEdit, relro); + } else { + setPlainText(this->ui->relroEdit, "N/A"); + } + } } // Add file hashes, analysis info and libraries - RzCoreLocked core(Core()); - RzBinFile *bf = rz_bin_cur(core->bin); RzBinInfo *binInfo = rz_bin_get_info(core->bin); setPlainText(ui->fileEdit, binInfo ? binInfo->file : ""); @@ -111,16 +114,25 @@ void Dashboard::updateContents() hashesLayout->addRow(new QLabel(label), hashLineEdit); } - CutterJson analinfo = Core()->cmdj("aaij"); - setPlainText(ui->functionsLineEdit, QString::number(analinfo["fcns"].toSt64())); - setPlainText(ui->xRefsLineEdit, QString::number(analinfo["xrefs"].toSt64())); - setPlainText(ui->callsLineEdit, QString::number(analinfo["calls"].toSt64())); - setPlainText(ui->stringsLineEdit, QString::number(analinfo["strings"].toSt64())); - setPlainText(ui->symbolsLineEdit, QString::number(analinfo["symbols"].toSt64())); - setPlainText(ui->importsLineEdit, QString::number(analinfo["imports"].toSt64())); - setPlainText(ui->coverageLineEdit, QString::number(analinfo["covrage"].toSt64()) + " bytes"); - setPlainText(ui->codeSizeLineEdit, QString::number(analinfo["codesz"].toSt64()) + " bytes"); - setPlainText(ui->percentageLineEdit, QString::number(analinfo["percent"].toSt64()) + "%"); + st64 fcns = rz_list_length(core->analysis->fcns); + st64 strs = rz_flag_count(core->flags, "str.*"); + st64 syms = rz_flag_count(core->flags, "sym.*"); + st64 imps = rz_flag_count(core->flags, "sym.imp.*"); + st64 code = rz_core_analysis_code_count(core); + st64 covr = rz_core_analysis_coverage_count(core); + st64 call = rz_core_analysis_calls_count(core); + ut64 xrfs = rz_analysis_xrefs_count(core->analysis); + double precentage = (code > 0) ? (covr * 100.0 / code) : 0; + + setPlainText(ui->functionsLineEdit, QString::number(fcns)); + setPlainText(ui->xRefsLineEdit, QString::number(xrfs)); + setPlainText(ui->callsLineEdit, QString::number(call)); + setPlainText(ui->stringsLineEdit, QString::number(strs)); + setPlainText(ui->symbolsLineEdit, QString::number(syms)); + setPlainText(ui->importsLineEdit, QString::number(imps)); + setPlainText(ui->coverageLineEdit, QString::number(covr) + " bytes"); + setPlainText(ui->codeSizeLineEdit, QString::number(code) + " bytes"); + setPlainText(ui->percentageLineEdit, QString::number(precentage) + "%"); // dunno: why not label->setText(lines.join("\n")? while (ui->verticalLayout_2->count() > 0) { @@ -153,9 +165,7 @@ void Dashboard::updateContents() if (Core()->getSignatureInfo().isEmpty()) { ui->certificateButton->setEnabled(false); } - if (!Core()->getFileVersionInfo().size()) { - ui->versioninfoButton->setEnabled(false); - } + ui->versioninfoButton->setEnabled(Core()->existsFileInfo()); } void Dashboard::on_certificateButton_clicked() diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index 6324467b..b59cfb34 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -564,7 +564,18 @@ void FunctionsWidget::refreshTree() importAddresses.insert(import.plt); } - mainAdress = (ut64)Core()->cmdj("iMj")["vaddr"].toUt64(); + mainAdress = RVA_INVALID; + RzCoreLocked core(Core()); + RzBinFile *bf = rz_bin_cur(core->bin); + if (bf) { + const RzBinAddr *binmain = + rz_bin_object_get_special_symbol(bf->o, RZ_BIN_SPECIAL_SYMBOL_MAIN); + if (binmain) { + int va = core->io->va || core->bin->is_debugger; + mainAdress = va ? rz_bin_object_addr_with_base(bf->o, binmain->vaddr) + : binmain->paddr; + } + } functionModel->updateCurrentIndex(); functionModel->endResetModel(); diff --git a/src/widgets/TypesWidget.cpp b/src/widgets/TypesWidget.cpp index 8e7a0e6e..ebdeace1 100644 --- a/src/widgets/TypesWidget.cpp +++ b/src/widgets/TypesWidget.cpp @@ -259,6 +259,10 @@ void TypesWidget::showTypesContextMenu(const QPoint &pt) void TypesWidget::on_actionExport_Types_triggered() { + char *str = rz_core_types_as_c_all(Core()->core(), true); + if (!str) { + return; + } QString filename = QFileDialog::getSaveFileName(this, tr("Save File"), Config()->getRecentFolder()); if (filename.isEmpty()) { @@ -272,8 +276,8 @@ void TypesWidget::on_actionExport_Types_triggered() return; } QTextStream fileOut(&file); - // TODO: use API for `tc` command once available - fileOut << Core()->cmd("tc"); + fileOut << str; + free(str); file.close(); } From 3855576be52bb4447946872db8e61661c749dcb5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 4 Jul 2022 10:39:10 +0200 Subject: [PATCH 136/240] Use meson==0.61.5 to fix libzip strcasecmp errors (#2991) --- .github/workflows/ccpp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 4adc9fd1..257f7469 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -71,7 +71,7 @@ jobs: - name: py dependencies run: | python3 -m pip install -U pip==21.3.1 - pip install meson + pip install meson==0.61.5 # https://github.com/rizinorg/cutter/runs/7170222817?check_suite_focus=true - name: Prepare package id shell: bash run: | From 569206fec8c5241c1c5b69faf40f84cd84d63148 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 4 Jul 2022 13:01:38 +0200 Subject: [PATCH 137/240] Update cutter-deps to v15 with macOS/arm64 included (#2990) --- scripts/fetch_deps.sh | 59 ++++++++++++++++++++++--------------------- 1 file changed, 30 insertions(+), 29 deletions(-) diff --git a/scripts/fetch_deps.sh b/scripts/fetch_deps.sh index 4079c6aa..fedace6d 100755 --- a/scripts/fetch_deps.sh +++ b/scripts/fetch_deps.sh @@ -1,54 +1,55 @@ #!/bin/bash +set -e + cd $(dirname "${BASH_SOURCE[0]}")/.. mkdir -p cutter-deps && cd cutter-deps -LINUX_FILE="cutter-deps-linux.tar.gz" -LINUX_MD5=eb2710548d951823e6b5340c33c8fc99 -LINUX_URL=https://github.com/rizinorg/cutter-deps/releases/download/v14/cutter-deps-linux.tar.gz +DEPS_FILE_linux_x86_64=cutter-deps-linux-x86_64.tar.gz +DEPS_SHA256_linux_x86_64=0721c85548bbcf31f6911cdb2227e5efb4a20c34262672d4cd2193db166b2f8c -MACOS_FILE="cutter-deps-macos.tar.gz" -MACOS_MD5=f921c007430eec38b06acef8cc0fe42a -MACOS_URL=https://github.com/rizinorg/cutter-deps/releases/download/v14/cutter-deps-macos.tar.gz +DEPS_FILE_macos_x86_64=cutter-deps-macos-x86_64.tar.gz +DEPS_SHA256_macos_x86_64=0a23fdec3012a8af76675d6f3ff39cf9df9b08c13d1156fb7ffcc0e495c9407f -WIN_FILE="cutter-deps-win.tar.gz" -WIN_MD5=09aa544e62cdd786df3598f1ff340f9e -WIN_URL=https://github.com/rizinorg/cutter-deps/releases/download/v14/cutter-deps-win.tar.gz +DEPS_FILE_macos_arm64=cutter-deps-macos-arm64.tar.gz +DEPS_SHA256_macos_arm64=f9b9a5569bd23c9b5e45836b82aba7576a5c53df4871380a55c370b9d7f88615 +DEPS_FILE_win_x86_64=cutter-deps-win-x86_64.tar.gz +DEPS_SHA256_win_x86_64=9ab4e89732a3df0859a26fd5de6d9f3cb80106cbe2539340af831ed298625076 + +DEPS_BASE_URL=https://github.com/rizinorg/cutter-deps/releases/download/v15 + +ARCH=x86_64 if [ "$OS" == "Windows_NT" ]; then - FILE="${WIN_FILE}" - MD5="${WIN_MD5}" - URL="${WIN_URL}" + PLATFORM=win else UNAME_S="$(uname -s)" if [ "$UNAME_S" == "Linux" ]; then - FILE="${LINUX_FILE}" - MD5="${LINUX_MD5}" - URL="${LINUX_URL}" + PLATFORM=linux elif [ "$UNAME_S" == "Darwin" ]; then - FILE="${MACOS_FILE}" - MD5="${MACOS_MD5}" - URL="${MACOS_URL}" + PLATFORM=macos + ARCH=$(uname -m) else echo "Unsupported Platform: uname -s => $UNAME_S, \$OS => $OS" exit 1 fi fi -curl -L "$URL" -o "$FILE" || exit 1 +DEPS_FILE=DEPS_FILE_${PLATFORM}_${ARCH} +DEPS_FILE=${!DEPS_FILE} +DEPS_SHA256=DEPS_SHA256_${PLATFORM}_${ARCH} +DEPS_SHA256=${!DEPS_SHA256} +DEPS_URL=${DEPS_BASE_URL}/${DEPS_FILE} -if [ "$UNAME_S" == "Darwin" ]; then - if [ "$(md5 -r "$FILE")" != "$MD5 $FILE" ]; then \ - echo "MD5 mismatch for file $FILE"; \ - exit 1; \ - else \ - echo "$FILE OK"; \ - fi -else - echo "$MD5 $FILE" | md5sum -c - || exit 1 +SHA256SUM=sha256sum +if ! command -v ${SHA256SUM} &> /dev/null; then + SHA256SUM="shasum -a 256" fi -tar -xf "$FILE" || exit 1 +curl -L "$DEPS_URL" -o "$DEPS_FILE" || exit 1 +echo "$DEPS_SHA256 $DEPS_FILE" | ${SHA256SUM} -c - || exit 1 + +tar -xf "$DEPS_FILE" || exit 1 if [ -f relocate.sh ]; then ./relocate.sh || exit 1 From 2c778d9b825145bf7617d0d64679140a221363ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Tue, 5 Jul 2022 14:06:06 +0200 Subject: [PATCH 138/240] Add Woodpecker macOS/arm64 CI (#2992) Package names have also been updated to the scheme used since v2.1.0, to better represent different architectures. --- .github/workflows/ccpp.yml | 6 ++--- .woodpecker/macos-arm64.yml | 49 +++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 3 deletions(-) create mode 100644 .woodpecker/macos-arm64.yml diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ccpp.yml index 257f7469..ff9bde5f 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ccpp.yml @@ -156,7 +156,7 @@ jobs: -ignore-glob=usr/lib/python3.9/**/* \ -verbose=2 find ./appdir -executable -type f -exec ldd {} \; | grep " => /usr" | cut -d " " -f 2-3 | sort | uniq - export APPIMAGE_FILE="Cutter-${PACKAGE_ID}-x64.Linux.AppImage" + export APPIMAGE_FILE="Cutter-${PACKAGE_ID}-Linux-x86_64.AppImage" mv Cutter-*-x86_64.AppImage "$APPIMAGE_FILE" echo PACKAGE_NAME=$APPIMAGE_FILE >> $GITHUB_ENV echo UPLOAD_ASSET_TYPE=application/x-executable >> $GITHUB_ENV @@ -173,7 +173,7 @@ jobs: source scripts/prepare_breakpad_macos.sh mkdir build cd build - PACKAGE_NAME=Cutter-${PACKAGE_ID}-x64.macOS + PACKAGE_NAME=Cutter-${PACKAGE_ID}-macOS-x86_64 cmake \ -DCMAKE_BUILD_TYPE=Release \ -DPYTHON_LIBRARY="$CUTTER_DEPS_PYTHON_PREFIX/lib/libpython3.9.dylib" \ @@ -219,7 +219,7 @@ jobs: cd mkdir build cd build - set PACKAGE_NAME=cutter-%PACKAGE_ID%-x64.Windows + set PACKAGE_NAME=Cutter-%PACKAGE_ID%-Windows-x86_64 cmake ^ -DCMAKE_BUILD_TYPE=Release ^ -DCUTTER_USE_BUNDLED_RIZIN=ON ^ diff --git a/.woodpecker/macos-arm64.yml b/.woodpecker/macos-arm64.yml new file mode 100644 index 00000000..96ce1457 --- /dev/null +++ b/.woodpecker/macos-arm64.yml @@ -0,0 +1,49 @@ +platform: darwin/arm64 + +pipeline: + fetch-deps: + image: /bin/bash + commands: + - scripts/fetch_deps.sh + build: + image: /bin/bash + commands: + - set -e + - export PACKAGE_ID=${CI_COMMIT_TAG=git-`date "+%Y-%m-%d"`-${CI_COMMIT_SHA}} + - export PACKAGE_NAME=Cutter-$${PACKAGE_ID}-macOS-arm64 + - source cutter-deps/env.sh + - source scripts/prepare_breakpad_macos.sh + - cmake -Bbuild -GNinja + -DCMAKE_BUILD_TYPE=Release + -DPYTHON_LIBRARY="$$CUTTER_DEPS_PYTHON_PREFIX/lib/libpython3.9.dylib" + -DPYTHON_INCLUDE_DIR="$$CUTTER_DEPS_PYTHON_PREFIX/include/python3.9" + -DPYTHON_EXECUTABLE="$$CUTTER_DEPS_PYTHON_PREFIX/bin/python3" + -DCUTTER_ENABLE_PYTHON=ON + -DCUTTER_ENABLE_PYTHON_BINDINGS=ON + -DCUTTER_ENABLE_CRASH_REPORTS=ON + -DCUTTER_USE_BUNDLED_RIZIN=ON + -DCUTTER_ENABLE_PACKAGING=ON + -DCUTTER_ENABLE_SIGDB=ON + -DCUTTER_PACKAGE_DEPENDENCIES=ON + -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON + -DCUTTER_PACKAGE_RZ_GHIDRA=ON + -DCUTTER_PACKAGE_JSDEC=ON + -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON + -DCUTTER_PACKAGE_RZ_LIBYARA=ON + -DCPACK_PACKAGE_FILE_NAME="$$PACKAGE_NAME" + -DCMAKE_FRAMEWORK_PATH="$$BREAKPAD_FRAMEWORK_DIR" + -DCPACK_BUNDLE_APPLE_CERT_APP="-" + - ninja -C build + package: + image: /bin/bash + commands: + - source cutter-deps/env.sh + - ninja -C build package + deploy: + when: + event: tag + tag: v* + image: /bin/bash + commands: + - gh release upload "${CI_COMMIT_TAG}" build/Cutter-*.dmg + secrets: [ github_token ] From 51c0a3d469df45387dab329459454b24a655ff7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 9 Jul 2022 12:48:48 +0200 Subject: [PATCH 139/240] Construct and destruct CutterCore singleton locally (Fix #2704) (#2994) Using Q_GLOBAL_STATIC meant that the CutterCore was destructed late as part of a binary destructor. It would then free the RzCore, calling for example the fini callbacks of all plugins. However global destructors in shared library plugins may have already been run at this point, leading to for example rz-ghidra's decompiler_mutex being used after destruction. Instead of the Q_GLOBAL_STATIC-managed global object, we are now handling the lifetime of the CutterCore ourselves and only injecting its instance to be accessed globally. This can also be a first step towards making the core instance completely local. --- src/CutterApplication.h | 1 + src/core/Cutter.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/CutterApplication.h b/src/CutterApplication.h index f8dc01e3..cd27a26a 100644 --- a/src/CutterApplication.h +++ b/src/CutterApplication.h @@ -50,6 +50,7 @@ private: private: bool m_FileAlreadyDropped; + CutterCore core; MainWindow *mainWindow; CutterCommandLineOptions clOptions; }; diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index f3c0f0de..e2d85297 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -24,7 +24,7 @@ #include #include -Q_GLOBAL_STATIC(CutterCore, uniqueInstance) +static CutterCore *uniqueInstance; #define RZ_JSON_KEY(name) static const QString name = QStringLiteral(#name) @@ -182,6 +182,10 @@ CutterCore::CutterCore(QObject *parent) coreMutex(QMutex::Recursive) #endif { + if (uniqueInstance) { + throw std::logic_error("Only one instance of CutterCore must exist"); + } + uniqueInstance = this; } CutterCore *CutterCore::instance() @@ -238,6 +242,8 @@ CutterCore::~CutterCore() rz_core_task_sync_end(&core_->tasks); rz_core_free(this->core_); rz_cons_free(); + assert(uniqueInstance == this); + uniqueInstance = nullptr; } RzCoreLocked CutterCore::core() From db0d4d85a600eddec46f1ac3d9b98f133e187ee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 9 Jul 2022 16:26:35 +0200 Subject: [PATCH 140/240] Use CutterJson for Signatures and rewrite JsonModel (#2997) This fixes a double-free in getSignatureInfo() when the string was already freed by the intermediate CutterJson. But actually just using this CutterJson makes more sense than the string anyway, so let's do that. The old JsonModel rebuilt the entire structure, defeating the main purpose of a custom model in comparison to the existing QTreeWidget. And since we are holding the json structures ourselves anyway, such a custom model does not have many benefits anyway. --- src/CMakeLists.txt | 2 - src/common/JsonModel.cpp | 149 +++++++-------------------------- src/common/JsonModel.h | 32 +------ src/common/JsonTreeItem.cpp | 104 ----------------------- src/common/JsonTreeItem.h | 39 --------- src/core/Cutter.cpp | 8 +- src/core/Cutter.h | 2 +- src/core/CutterJson.h | 1 - src/widgets/CutterTreeView.cpp | 9 +- src/widgets/CutterTreeView.h | 2 + src/widgets/Dashboard.cpp | 48 +++++------ 11 files changed, 67 insertions(+), 329 deletions(-) delete mode 100644 src/common/JsonTreeItem.cpp delete mode 100644 src/common/JsonTreeItem.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 47357c69..ba6691c9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -72,7 +72,6 @@ set(SOURCES widgets/CutterTreeWidget.cpp widgets/GraphWidget.cpp widgets/OverviewWidget.cpp - common/JsonTreeItem.cpp common/JsonModel.cpp dialogs/VersionInfoDialog.cpp widgets/FlirtWidget.cpp @@ -222,7 +221,6 @@ set(HEADER_FILES widgets/CutterTreeWidget.h widgets/GraphWidget.h widgets/OverviewWidget.h - common/JsonTreeItem.h common/JsonModel.h dialogs/VersionInfoDialog.h widgets/FlirtWidget.h diff --git a/src/common/JsonModel.cpp b/src/common/JsonModel.cpp index 4b1ef628..4bc01cb4 100644 --- a/src/common/JsonModel.cpp +++ b/src/common/JsonModel.cpp @@ -1,123 +1,38 @@ #include "JsonModel.h" -#include - -JsonModel::JsonModel(QObject *parent) : QAbstractItemModel(parent) +QTreeWidgetItem *Cutter::jsonTreeWidgetItem(const QString &key, const CutterJson &json) { - mRootItem = new JsonTreeItem; - mHeaders.append("key"); - mHeaders.append("value"); -} - -JsonModel::~JsonModel() -{ - delete mRootItem; -} - -bool JsonModel::load(QIODevice *device) -{ - return loadJson(device->readAll()); -} - -bool JsonModel::loadJson(const QByteArray &json) -{ - mDocument = QJsonDocument::fromJson(json); - - if (!mDocument.isNull()) { - beginResetModel(); - delete mRootItem; - if (mDocument.isArray()) { - mRootItem = JsonTreeItem::load(QJsonValue(mDocument.array())); - } else { - mRootItem = JsonTreeItem::load(QJsonValue(mDocument.object())); + QString val; + switch (json.type()) { + case RZ_JSON_STRING: + val = json.toString(); + break; + case RZ_JSON_BOOLEAN: + val = json.toBool() ? "true" : "false"; + break; + case RZ_JSON_DOUBLE: + val = QString::number(json.lowLevelValue()->num.dbl_value); + break; + case RZ_JSON_INTEGER: + val = QString::number(json.toUt64()); + break; + case RZ_JSON_NULL: + val = "null"; + break; + case RZ_JSON_OBJECT: + case RZ_JSON_ARRAY: + break; + } + auto r = new QTreeWidgetItem(QStringList({ key, val })); + if (json.type() == RZ_JSON_ARRAY) { + size_t i = 0; + for (const auto &child : json) { + r->addChild(jsonTreeWidgetItem(QString::number(i++), child)); + } + } else if (json.type() == RZ_JSON_OBJECT) { + for (const auto &child : json) { + r->addChild(jsonTreeWidgetItem(child.key(), child)); } - endResetModel(); - return true; } - return false; -} - -QVariant JsonModel::data(const QModelIndex &index, int role) const -{ - - if (!index.isValid()) - return QVariant(); - - JsonTreeItem *item = static_cast(index.internalPointer()); - - if (role == Qt::DisplayRole) { - - if (index.column() == 0) - return QString("%1").arg(item->key()); - - if (index.column() == 1) - return QString("%1").arg(item->value()); - } - - return QVariant(); -} - -QVariant JsonModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (role != Qt::DisplayRole) - return QVariant(); - - if (orientation == Qt::Horizontal) { - - return mHeaders.value(section); - } else - return QVariant(); -} - -QModelIndex JsonModel::index(int row, int column, const QModelIndex &parent) const -{ - if (!hasIndex(row, column, parent)) - return QModelIndex(); - - JsonTreeItem *parentItem; - - if (!parent.isValid()) - parentItem = mRootItem; - else - parentItem = static_cast(parent.internalPointer()); - - JsonTreeItem *childItem = parentItem->child(row); - if (childItem) - return createIndex(row, column, childItem); - else - return QModelIndex(); -} - -QModelIndex JsonModel::parent(const QModelIndex &index) const -{ - if (!index.isValid()) - return QModelIndex(); - - JsonTreeItem *childItem = static_cast(index.internalPointer()); - JsonTreeItem *parentItem = childItem->parent(); - - if (parentItem == mRootItem) - return QModelIndex(); - - return createIndex(parentItem->row(), 0, parentItem); -} - -int JsonModel::rowCount(const QModelIndex &parent) const -{ - JsonTreeItem *parentItem; - if (parent.column() > 0) - return 0; - - if (!parent.isValid()) - parentItem = mRootItem; - else - parentItem = static_cast(parent.internalPointer()); - - return parentItem->childCount(); -} - -int JsonModel::columnCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent) - return 2; + return r; } diff --git a/src/common/JsonModel.h b/src/common/JsonModel.h index 4b5c7cdd..5af02ab6 100644 --- a/src/common/JsonModel.h +++ b/src/common/JsonModel.h @@ -2,37 +2,13 @@ #ifndef JSONMODEL_H #define JSONMODEL_H -#include -#include -#include -#include -#include -#include +#include +#include "CutterJson.h" -#include "JsonTreeItem.h" +namespace Cutter { -class JsonTreeItem; +QTreeWidgetItem *jsonTreeWidgetItem(const QString &key, const CutterJson &json); -class JsonModel : public QAbstractItemModel -{ - -public: - explicit JsonModel(QObject *parent = nullptr); - bool load(QIODevice *device); - bool loadJson(const QByteArray &json); - QVariant data(const QModelIndex &index, int role) const Q_DECL_OVERRIDE; - QVariant headerData(int section, Qt::Orientation orientation, int role) const Q_DECL_OVERRIDE; - QModelIndex index(int row, int column, - const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - QModelIndex parent(const QModelIndex &index) const Q_DECL_OVERRIDE; - int rowCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - int columnCount(const QModelIndex &parent = QModelIndex()) const Q_DECL_OVERRIDE; - ~JsonModel(); - -private: - JsonTreeItem *mRootItem; - QJsonDocument mDocument; - QStringList mHeaders; }; #endif // JSONMODEL_H diff --git a/src/common/JsonTreeItem.cpp b/src/common/JsonTreeItem.cpp deleted file mode 100644 index 3a16dbd7..00000000 --- a/src/common/JsonTreeItem.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include "JsonTreeItem.h" - -JsonTreeItem::JsonTreeItem(JsonTreeItem *parent) -{ - mParent = parent; -} - -JsonTreeItem::~JsonTreeItem() -{ - qDeleteAll(mChilds); -} - -void JsonTreeItem::appendChild(JsonTreeItem *item) -{ - mChilds.append(item); -} - -JsonTreeItem *JsonTreeItem::child(int row) -{ - return mChilds.value(row); -} - -JsonTreeItem *JsonTreeItem::parent() -{ - return mParent; -} - -int JsonTreeItem::childCount() const -{ - return mChilds.count(); -} - -int JsonTreeItem::row() const -{ - if (mParent) - return mParent->mChilds.indexOf(const_cast(this)); - - return 0; -} - -void JsonTreeItem::setKey(const QString &key) -{ - mKey = key; -} - -void JsonTreeItem::setValue(const QString &value) -{ - mValue = value; -} - -void JsonTreeItem::setType(const QJsonValue::Type &type) -{ - mType = type; -} - -QString JsonTreeItem::key() const -{ - return mKey; -} - -QString JsonTreeItem::value() const -{ - return mValue; -} - -QJsonValue::Type JsonTreeItem::type() const -{ - return mType; -} - -JsonTreeItem *JsonTreeItem::load(const QJsonValue &value, JsonTreeItem *parent) -{ - JsonTreeItem *rootItem = new JsonTreeItem(parent); - rootItem->setKey("root"); - - if (value.isObject()) { - - // Get all QJsonValue childs - for (const QString &key : value.toObject().keys()) { - QJsonValue v = value.toObject().value(key); - JsonTreeItem *child = load(v, rootItem); - child->setKey(key); - child->setType(v.type()); - rootItem->appendChild(child); - } - - } else if (value.isArray()) { - // Get all QJsonValue childs - int index = 0; - for (const QJsonValue &v : value.toArray()) { - - JsonTreeItem *child = load(v, rootItem); - child->setKey(QString::number(index)); - child->setType(v.type()); - rootItem->appendChild(child); - ++index; - } - } else { - rootItem->setValue(value.toVariant().toString()); - rootItem->setType(value.type()); - } - - return rootItem; -} diff --git a/src/common/JsonTreeItem.h b/src/common/JsonTreeItem.h deleted file mode 100644 index 780a3799..00000000 --- a/src/common/JsonTreeItem.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef JSONTREEITEM_H -#define JSONTREEITEM_H - -#include -#include -#include -#include -#include -#include - -#include "JsonModel.h" - -class JsonTreeItem -{ -public: - JsonTreeItem(JsonTreeItem *parent = nullptr); - ~JsonTreeItem(); - void appendChild(JsonTreeItem *item); - JsonTreeItem *child(int row); - JsonTreeItem *parent(); - int childCount() const; - int row() const; - void setKey(const QString &key); - void setValue(const QString &value); - void setType(const QJsonValue::Type &type); - QString key() const; - QString value() const; - QJsonValue::Type type() const; - static JsonTreeItem *load(const QJsonValue &value, JsonTreeItem *parent = nullptr); - -private: - QString mKey; - QString mValue; - QJsonValue::Type mType; - QList mChilds; - JsonTreeItem *mParent; -}; - -#endif // JSONTREEITEM_H diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index e2d85297..a8a8c038 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1440,7 +1440,7 @@ bool CutterCore::registerDecompiler(Decompiler *decompiler) return true; } -QString CutterCore::getSignatureInfo() +CutterJson CutterCore::getSignatureInfo() { CORE_LOCK(); RzBinFile *cur = rz_bin_cur(core->bin); @@ -1452,11 +1452,7 @@ QString CutterCore::getSignatureInfo() if (!signature) { return {}; } - auto sig = parseJson(signature, nullptr); - if (sig.size() == 0) { - return {}; - } - return fromOwnedCharPtr(signature); + return parseJson(signature, nullptr); } bool CutterCore::existsFileInfo() diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 9aa90b18..bdddd342 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -569,7 +569,7 @@ public: bool registerDecompiler(Decompiler *decompiler); RVA getOffsetJump(RVA addr); - QString getSignatureInfo(); + CutterJson getSignatureInfo(); bool existsFileInfo(); void setGraphEmpty(bool empty); bool isGraphEmpty(); diff --git a/src/core/CutterJson.h b/src/core/CutterJson.h index e8dd9819..e733ca6c 100644 --- a/src/core/CutterJson.h +++ b/src/core/CutterJson.h @@ -70,7 +70,6 @@ public: iterator end() const { return iterator(nullptr, nullptr); } bool toBool() const { return value && value->type == RZ_JSON_BOOLEAN && value->num.u_value; } - QString toJson() const { return rz_json_as_string(value); } st64 toSt64() const { return value && value->type == RZ_JSON_INTEGER ? value->num.s_value : 0; } ut64 toUt64() const { return value && value->type == RZ_JSON_INTEGER ? value->num.u_value : 0; } diff --git a/src/widgets/CutterTreeView.cpp b/src/widgets/CutterTreeView.cpp index f26fc08c..233cdd80 100644 --- a/src/widgets/CutterTreeView.cpp +++ b/src/widgets/CutterTreeView.cpp @@ -4,8 +4,13 @@ CutterTreeView::CutterTreeView(QWidget *parent) : QTreeView(parent), ui(new Ui::CutterTreeView()) { ui->setupUi(this); - this->setSelectionMode(QAbstractItemView::ExtendedSelection); - this->setUniformRowHeights(true); + applyCutterStyle(this); } CutterTreeView::~CutterTreeView() {} + +void CutterTreeView::applyCutterStyle(QTreeView *view) +{ + view->setSelectionMode(QAbstractItemView::ExtendedSelection); + view->setUniformRowHeights(true); +} diff --git a/src/widgets/CutterTreeView.h b/src/widgets/CutterTreeView.h index 46dfcccd..33600bc3 100644 --- a/src/widgets/CutterTreeView.h +++ b/src/widgets/CutterTreeView.h @@ -19,6 +19,8 @@ public: explicit CutterTreeView(QWidget *parent = nullptr); ~CutterTreeView(); + static void applyCutterStyle(QTreeView *view); + private: std::unique_ptr ui; }; diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index 3715bc36..f73b4cc1 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -2,7 +2,6 @@ #include "ui_Dashboard.h" #include "common/Helpers.h" #include "common/JsonModel.h" -#include "common/JsonTreeItem.h" #include "common/TempConfig.h" #include "dialogs/VersionInfoDialog.h" @@ -162,7 +161,7 @@ void Dashboard::updateContents() ui->verticalLayout_2->addSpacerItem(spacer); // Check if signature info and version info available - if (Core()->getSignatureInfo().isEmpty()) { + if (!Core()->getSignatureInfo().size()) { ui->certificateButton->setEnabled(false); } ui->versioninfoButton->setEnabled(Core()->existsFileInfo()); @@ -170,33 +169,24 @@ void Dashboard::updateContents() void Dashboard::on_certificateButton_clicked() { - static QDialog *viewDialog = nullptr; - static CutterTreeView *view = nullptr; - static JsonModel *model = nullptr; - static QString qstrCertificates; - if (!viewDialog) { - viewDialog = new QDialog(this); - view = new CutterTreeView(viewDialog); - model = new JsonModel(); - qstrCertificates = Core()->getSignatureInfo(); - } - if (!viewDialog->isVisible()) { - std::string strCertificates = qstrCertificates.toUtf8().constData(); - model->loadJson(QByteArray::fromStdString(strCertificates)); - view->setModel(model); - view->expandAll(); - view->resize(900, 600); - QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - sizePolicy.setHorizontalStretch(0); - sizePolicy.setVerticalStretch(0); - sizePolicy.setHeightForWidth(view->sizePolicy().hasHeightForWidth()); - viewDialog->setSizePolicy(sizePolicy); - viewDialog->setMinimumSize(QSize(900, 600)); - viewDialog->setMaximumSize(QSize(900, 600)); - viewDialog->setSizeGripEnabled(false); - viewDialog->setWindowTitle("Certificates"); - viewDialog->show(); - } + QDialog dialog(this); + auto view = new QTreeWidget(&dialog); + view->setHeaderLabels({ tr("Key"), tr("Value") }); + view->addTopLevelItem(Cutter::jsonTreeWidgetItem(QString("<%1>").arg(tr("root")), + Core()->getSignatureInfo())); + CutterTreeView::applyCutterStyle(view); + view->expandAll(); + view->resize(900, 600); + QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + sizePolicy.setHorizontalStretch(0); + sizePolicy.setVerticalStretch(0); + sizePolicy.setHeightForWidth(view->sizePolicy().hasHeightForWidth()); + dialog.setSizePolicy(sizePolicy); + dialog.setMinimumSize(QSize(900, 600)); + dialog.setMaximumSize(QSize(900, 600)); + dialog.setSizeGripEnabled(false); + dialog.setWindowTitle("Certificates"); + dialog.exec(); } void Dashboard::on_versioninfoButton_clicked() From 44b7a7997a70d5537d3f02223c103718e15bd93f Mon Sep 17 00:00:00 2001 From: billow Date: Mon, 1 Aug 2022 23:57:16 +0800 Subject: [PATCH 141/240] Convert disassembly (pd pdj pdJ) to rizin API (#2996) --- rizin | 2 +- src/core/Cutter.cpp | 101 ++++++++++++++++++++------- src/core/Cutter.h | 4 ++ src/dialogs/XrefsDialog.cpp | 14 +++- src/menus/DisassemblyContextMenu.cpp | 24 ++++--- 5 files changed, 105 insertions(+), 40 deletions(-) diff --git a/rizin b/rizin index 0fc9c968..b79201b4 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 0fc9c9682e8a74245e4f24b84508f2bb6b185328 +Subproject commit b79201b49a0d687c854b6e2f0c88fc8a7f2afa61 diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index a8a8c038..1cd9ad50 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -377,6 +377,37 @@ QString CutterCore::cmd(const char *str) return o; } +QString CutterCore::getFunctionExecOut(const std::function &fcn, const RVA addr) +{ + CORE_LOCK(); + + RVA offset = core->offset; + seekSilent(addr); + QString o = {}; + rz_cons_push(); + bool is_pipe = core->is_pipe; + core->is_pipe = true; + + if (!fcn(core)) { + core->is_pipe = is_pipe; + rz_cons_pop(); + goto clean_return; + } + + core->is_pipe = is_pipe; + rz_cons_filter(); + o = rz_cons_get_buffer(); + + rz_cons_pop(); + rz_cons_echo(NULL); + +clean_return: + if (offset != core->offset) { + seekSilent(offset); + } + return o; +} + bool CutterCore::isRedirectableDebugee() { if (!currentlyDebugging || currentlyAttachedToPID != -1) { @@ -1055,24 +1086,23 @@ RVA CutterCore::prevOpAddr(RVA startAddr, int count) RVA CutterCore::nextOpAddr(RVA startAddr, int count) { CORE_LOCK(); - - CutterJson array = - Core()->cmdj("pdj " + QString::number(count + 1) + " @ " + QString::number(startAddr)); - if (!array.size()) { - return startAddr + 1; + auto vec = reinterpret_cast(returnAtSeek( + [&]() { + return rz_core_analysis_bytes(core, core->block, (int)core->blocksize, count + 1); + }, + startAddr)); + RVA addr = startAddr + 1; + if (!vec) { + return addr; } - - CutterJson instValue = array.last(); - if (instValue.type() != RZ_JSON_OBJECT) { - return startAddr + 1; + auto ab = reinterpret_cast(rz_pvector_tail(vec)); + if (!(ab && ab->op)) { + rz_pvector_free(vec); + return addr; } - - RVA offset = instValue[RJsonKey::offset].toRVA(); - if (offset == RVA_INVALID) { - return startAddr + 1; - } - - return offset; + addr = ab->op->addr; + rz_pvector_free(vec); + return addr; } RVA CutterCore::getOffset() @@ -4176,18 +4206,35 @@ void CutterCore::loadPDB(const QString &file) QList CutterCore::disassembleLines(RVA offset, int lines) { - CutterJson array = cmdj(QString("pdJ ") + QString::number(lines) + QString(" @ ") - + QString::number(offset)); - QList r; - - for (CutterJson object : array) { - DisassemblyLine line; - line.offset = object[RJsonKey::offset].toRVA(); - line.text = ansiEscapeToHtml(object[RJsonKey::text].toString()); - line.arrow = object[RJsonKey::arrow].toRVA(); - r << line; + CORE_LOCK(); + RzPVector *vec = 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); + + QList r; + for (const auto &t : CutterPVector(vec)) { + DisassemblyLine line; + line.offset = t->offset; + line.text = ansiEscapeToHtml(t->text); + line.arrow = t->arrow; + r << line; + } + rz_pvector_free(vec); return r; } @@ -4354,7 +4401,7 @@ QString CutterCore::ansiEscapeToHtml(const QString &text) int len; char *html = rz_cons_html_filter(text.toUtf8().constData(), &len); if (!html) { - return QString(); + return {}; } QString r = QString::fromUtf8(html, len); rz_mem_free(html); diff --git a/src/core/Cutter.h b/src/core/Cutter.h index bdddd342..e544f3a5 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -81,6 +81,10 @@ public: RVA getOffset() const { return core_->offset; } /* Core functions (commands) */ + /* Almost the same as core_cmd_raw, + * only executes std::function instead of char* */ + QString getFunctionExecOut(const std::function &fcn, + const RVA addr = RVA_INVALID); static QString sanitizeStringForCommand(QString s); /** * @brief send a command to Rizin diff --git a/src/dialogs/XrefsDialog.cpp b/src/dialogs/XrefsDialog.cpp index 0a721e71..c7803562 100644 --- a/src/dialogs/XrefsDialog.cpp +++ b/src/dialogs/XrefsDialog.cpp @@ -131,8 +131,18 @@ void XrefsDialog::updatePreview(RVA addr) tempConfig.set("asm.lines", false); tempConfig.set("asm.bytes", false); - // Use cmd because cmRaw cannot handle the output properly. Why? - QString disas = Core()->cmd("pd--20 @ " + QString::number(addr)); + QString disas = Core()->getFunctionExecOut( + [](RzCore *core) { + ut64 offset = core->offset; + if (!rz_core_prevop_addr(core, core->offset, 20, &offset)) { + offset = rz_core_prevop_addr_force(core, core->offset, 20); + } + rz_core_seek(core, offset, true); + rz_core_print_disasm(core, core->offset, core->block, (int)core->blocksize, 40, + NULL, NULL); + return true; + }, + addr); ui->previewTextEdit->document()->setHtml(disas); // Does it make any sense? diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index f3f2dcfb..f08b8c5e 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -726,19 +726,23 @@ void DisassemblyContextMenu::on_actionNopInstruction_triggered() void DisassemblyContextMenu::showReverseJmpQuery() { - QString type; - - CutterJson array = Core()->cmdj("pdj 1 @ " + RzAddressString(offset)); - if (!array.size()) { + actionJmpReverse.setVisible(false); + RzCoreLocked core(Core()); + auto vec = reinterpret_cast(Core()->returnAtSeek( + [&]() { return rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); }, + offset)); + if (!vec) { return; } - - type = array.first()["type"].toString(); - if (type == "cjmp") { - actionJmpReverse.setVisible(true); - } else { - actionJmpReverse.setVisible(false); + auto ab = reinterpret_cast(rz_pvector_head(vec)); + if (!(ab && ab->op)) { + rz_pvector_free(vec); + return; } + if (ab->op->type == RZ_ANALYSIS_OP_TYPE_CJMP) { + actionJmpReverse.setVisible(true); + } + rz_pvector_free(vec); } void DisassemblyContextMenu::on_actionJmpReverse_triggered() From 9e2201aa81656a2005a3609244b89ff1c90084e4 Mon Sep 17 00:00:00 2001 From: Riccardo Schirone Date: Sat, 6 Aug 2022 21:50:41 +0200 Subject: [PATCH 142/240] Mention OBS install mode for Linux (#3006) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4962b466..5642875b 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Cutter is a free and open-source reverse engineering platform powered by [rizin] Cutter release binaries for all major platforms (Linux, macOS, Windows) can be downloaded from [GitHub Releases](https://github.com/rizinorg/cutter/releases). -- **Linux**: Download the `.AppImage` file. Then make it executable and run as below or use [AppImageLauncher](https://github.com/TheAssassin/AppImageLauncher). +- **Linux**: If your distribution provides it, check for `cutter` package in your package manager (or `cutter-re`). If not available there, we have setup repositories in [OBS](https://openbuildservice.org/) for some common distributions. Look at [https://software.opensuse.org/package/cutter-re](https://software.opensuse.org/download/package?package=cutter-re&project=home%3ARizinOrg) and follow the instructions there. Otherwise download the `.AppImage` file from our release, make it executable and run as below or use [AppImageLauncher](https://github.com/TheAssassin/AppImageLauncher). `chmod +x Cutter*.AppImage; ./Cutter*.AppImage` - **macOS**: Download the `.dmg` file or use [Homebrew Cask](https://github.com/Homebrew/homebrew-cask): From 35f9bfe135f5d87d8f0f47e2709b8dd952e42906 Mon Sep 17 00:00:00 2001 From: billow Date: Tue, 9 Aug 2022 09:29:08 +0800 Subject: [PATCH 143/240] Update rizin and version API (#3008) --- dist/bundle_python.ps1 | 2 +- rizin | 2 +- src/core/Cutter.cpp | 8 ++++---- src/core/Cutter.h | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/dist/bundle_python.ps1 b/dist/bundle_python.ps1 index b421ed98..7e47c0d0 100644 --- a/dist/bundle_python.ps1 +++ b/dist/bundle_python.ps1 @@ -2,7 +2,7 @@ $arch = $args[0] $dist = $args[1] $py_version = (python --version).Split()[1] -$py_base = "python" + $py_version[0] + $py_version[2] +$py_base = "python" + $py_version.Split('.')[0] + $py_version.Split('.')[1] $py_platform = If ($arch -eq "x64") {"amd64"} Else {"win32"} $py_url = "https://www.python.org/ftp/python/${py_version}/python-${py_version}-embed-${py_platform}.zip" diff --git a/rizin b/rizin index b79201b4..215e4925 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit b79201b49a0d687c854b6e2f0c88fc8a7f2afa61 +Subproject commit 215e49253d3a35e1aae340b7ae8465018254ae87 diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 1cd9ad50..5c7b515f 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -4297,10 +4297,9 @@ void CutterCore::loadScript(const QString &scriptname) triggerRefreshAll(); } -QString CutterCore::getRizinVersionReadable() +QString CutterCore::getRizinVersionReadable(const char *program) { - return QString("%1 (%2)").arg(QString::fromUtf8(RZ_VERSION), - QString::fromUtf8(RZ_GITTIP).left(7)); + return fromOwnedCharPtr(rz_version_str(program)); } QString CutterCore::getVersionInformation() @@ -4337,7 +4336,8 @@ QString CutterCore::getVersionInformation() /* ... */ { NULL, NULL } }; - versionInfo.append(QString("%1 rz\n").arg(getRizinVersionReadable())); + versionInfo.append(getRizinVersionReadable()); + versionInfo.append("\n"); for (i = 0; vcs[i].name; i++) { struct vcs_t *v = &vcs[i]; const char *name = v->callback(); diff --git a/src/core/Cutter.h b/src/core/Cutter.h index e544f3a5..574d5258 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -201,7 +201,7 @@ public: { return asyncCmdEsil(command.toUtf8().constData(), task); } - QString getRizinVersionReadable(); + QString getRizinVersionReadable(const char *program = nullptr); QString getVersionInformation(); CutterJson parseJson(char *res, const char *cmd = nullptr); From a4a4b9d2ec2d88b9c4b1cabdbffb116ca912958b Mon Sep 17 00:00:00 2001 From: billow Date: Tue, 9 Aug 2022 23:51:20 +0800 Subject: [PATCH 144/240] Convert to rizin APIs `pc*` `px*` (#3007) --- src/core/Cutter.cpp | 22 ++++++++----- src/core/Cutter.h | 12 +++++++ src/core/MainWindow.cpp | 70 ++++++++++++++++++++++++++++------------- 3 files changed, 75 insertions(+), 29 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 5c7b515f..78e82ec4 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -4246,28 +4246,36 @@ QList CutterCore::disassembleLines(RVA offset, int lines) */ QString CutterCore::hexdump(RVA address, int size, HexdumpFormats format) { - QString command = "px"; + CORE_LOCK(); + char *res = nullptr; switch (format) { case HexdumpFormats::Normal: + res = rz_core_print_hexdump_or_hexdiff_str(core, RZ_OUTPUT_MODE_STANDARD, address, size, + false); break; case HexdumpFormats::Half: - command += "h"; + res = rz_core_print_dump_str(core, RZ_OUTPUT_MODE_STANDARD, address, 2, size, + RZ_CORE_PRINT_FORMAT_TYPE_HEXADECIMAL); break; case HexdumpFormats::Word: - command += "w"; + res = rz_core_print_dump_str(core, RZ_OUTPUT_MODE_STANDARD, address, 4, size, + RZ_CORE_PRINT_FORMAT_TYPE_HEXADECIMAL); break; case HexdumpFormats::Quad: - command += "q"; + res = rz_core_print_dump_str(core, RZ_OUTPUT_MODE_STANDARD, address, 8, size, + RZ_CORE_PRINT_FORMAT_TYPE_HEXADECIMAL); break; case HexdumpFormats::Signed: - command += "d"; + res = rz_core_print_dump_str(core, RZ_OUTPUT_MODE_STANDARD, address, 1, size, + RZ_CORE_PRINT_FORMAT_TYPE_INTEGER); break; case HexdumpFormats::Octal: - command += "o"; + res = rz_core_print_dump_str(core, RZ_OUTPUT_MODE_STANDARD, address, 1, size, + RZ_CORE_PRINT_FORMAT_TYPE_OCTAL); break; } - return cmdRawAt(QString("%1 %2").arg(command).arg(size), address); + return fromOwnedCharPtr(res); } QByteArray CutterCore::hexStringToBytes(const QString &hex) diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 574d5258..dd042109 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -17,6 +17,7 @@ #include #include #include +#include class AsyncTaskManager; class BasicInstructionHighlighter; @@ -169,6 +170,17 @@ public: return ret; } + std::unique_ptr> seekTemp(RVA address) + { + auto seekBack = [&](const RVA *x) { + seekSilent(*x); + delete x; + }; + std::unique_ptr p { new RVA(getOffset()), seekBack }; + seekSilent(address); + return p; + } + CutterJson cmdj(const char *str); CutterJson cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); } CutterJson cmdjAt(const char *str, RVA address); diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index e599809e..339884cc 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -149,7 +149,7 @@ void MainWindow::initUI() &MainWindow::addExtraDisassembly); connect(ui->actionExtraHexdump, &QAction::triggered, this, &MainWindow::addExtraHexdump); connect(ui->actionCommitChanges, &QAction::triggered, this, - [this]() { Core()->commitWriteCache(); }); + []() { Core()->commitWriteCache(); }); ui->actionCommitChanges->setEnabled(false); connect(Core(), &CutterCore::ioCacheChanged, ui->actionCommitChanges, &QAction::setEnabled); @@ -1692,35 +1692,55 @@ void MainWindow::on_actionImportPDB_triggered() } } +#define TYPE_BIG_ENDIAN(type, big_endian) big_endian ? type##_BE : type##_LE + void MainWindow::on_actionExport_as_code_triggered() { QStringList filters; - QMap cmdMap; + QMap typMap; + const bool big_endian = Core()->getConfigb("big_endian"); filters << tr("C uin8_t array (*.c)"); - cmdMap[filters.last()] = "pc"; + typMap[filters.last()] = RZ_LANG_BYTE_ARRAY_C_CPP_BYTES; filters << tr("C uin16_t array (*.c)"); - cmdMap[filters.last()] = "pch"; + typMap[filters.last()] = TYPE_BIG_ENDIAN(RZ_LANG_BYTE_ARRAY_C_CPP_HALFWORDS, big_endian); filters << tr("C uin32_t array (*.c)"); - cmdMap[filters.last()] = "pcw"; + typMap[filters.last()] = TYPE_BIG_ENDIAN(RZ_LANG_BYTE_ARRAY_C_CPP_WORDS, big_endian); filters << tr("C uin64_t array (*.c)"); - cmdMap[filters.last()] = "pcd"; - filters << tr("C string (*.c)"); - cmdMap[filters.last()] = "pcs"; - filters << tr("Shell-script that reconstructs the bin (*.sh)"); - cmdMap[filters.last()] = "pcS"; + typMap[filters.last()] = TYPE_BIG_ENDIAN(RZ_LANG_BYTE_ARRAY_C_CPP_DOUBLEWORDS, big_endian); + + filters << tr("Go array (*.go)"); + typMap[filters.last()] = RZ_LANG_BYTE_ARRAY_GOLANG; + filters << tr("Java array (*.java)"); + typMap[filters.last()] = RZ_LANG_BYTE_ARRAY_JAVA; filters << tr("JSON array (*.json)"); - cmdMap[filters.last()] = "pcj"; - filters << tr("JavaScript array (*.js)"); - cmdMap[filters.last()] = "pcJ"; + typMap[filters.last()] = RZ_LANG_BYTE_ARRAY_JSON; + filters << tr("Kotlin array (*.kt)"); + typMap[filters.last()] = RZ_LANG_BYTE_ARRAY_KOTLIN; + + filters << tr("Javascript array (*.js)"); + typMap[filters.last()] = RZ_LANG_BYTE_ARRAY_NODEJS; + filters << tr("ObjectiveC array (*.m)"); + typMap[filters.last()] = RZ_LANG_BYTE_ARRAY_OBJECTIVE_C; filters << tr("Python array (*.py)"); - cmdMap[filters.last()] = "pcp"; + typMap[filters.last()] = RZ_LANG_BYTE_ARRAY_PYTHON; + filters << tr("Rust array (*.rs)"); + typMap[filters.last()] = RZ_LANG_BYTE_ARRAY_RUST; + + filters << tr("Swift array (*.swift)"); + typMap[filters.last()] = RZ_LANG_BYTE_ARRAY_SWIFT; filters << tr("Print 'wx' Rizin commands (*.rz)"); - cmdMap[filters.last()] = "pc*"; + typMap[filters.last()] = RZ_LANG_BYTE_ARRAY_RIZIN; + filters << tr("Shell-script that reconstructs the bin (*.sh)"); + typMap[filters.last()] = RZ_LANG_BYTE_ARRAY_BASH; filters << tr("GAS .byte blob (*.asm, *.s)"); - cmdMap[filters.last()] = "pca"; - filters << tr(".bytes with instructions in comments (*.txt)"); - cmdMap[filters.last()] = "pcA"; + typMap[filters.last()] = RZ_LANG_BYTE_ARRAY_ASM; + + filters << tr("Yara (*.yar)"); + typMap[filters.last()] = RZ_LANG_BYTE_ARRAY_YARA; + /* special case */ + QString instructionsInComments = tr(".bytes with instructions in comments (*.txt)"); + filters << instructionsInComments; QFileDialog dialog(this, tr("Export as code")); dialog.setAcceptMode(QFileDialog::AcceptSave); @@ -1736,13 +1756,19 @@ void MainWindow::on_actionExport_as_code_triggered() qWarning() << "Can't open file"; return; } + TempConfig tempConfig; tempConfig.set("io.va", false); QTextStream fileOut(&file); - QString &cmd = cmdMap[dialog.selectedNameFilter()]; - - // Use cmd because cmdRaw would not handle such input - fileOut << Core()->cmd(cmd + " $s @ 0"); + auto ps = core->seekTemp(0); + auto rc = core->core(); + std::unique_ptr string { + dialog.selectedNameFilter() != instructionsInComments + ? rz_lang_byte_array(rc->block, rc->blocksize, typMap[dialog.selectedNameFilter()]) + : rz_core_print_bytes_with_inst(rc, rc->block, rc->offset, rc->blocksize), + free + }; + fileOut << string.get(); } void MainWindow::on_actionApplySigFromFile_triggered() From 278b4e19b906b242b9c1f31a804d8dfddbc480b1 Mon Sep 17 00:00:00 2001 From: Jeremy Rifkin <51220084+jeremy-rifkin@users.noreply.github.com> Date: Wed, 10 Aug 2022 09:05:01 -0400 Subject: [PATCH 145/240] Update GraphGridLayout documentation (#3000) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Updated GraphGridLayout documentation * Don't use potentially misleading name "segment tree" . Not exactly segment tree (although sometimes called that), and for the purpose of high level understanding how graph layout works doesn't matter what it is. Any data structure which provides required queries could be used. Co-authored-by: Kārlis Seņko --- src/widgets/GraphGridLayout.cpp | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/widgets/GraphGridLayout.cpp b/src/widgets/GraphGridLayout.cpp index 0f636e2f..cf100e24 100644 --- a/src/widgets/GraphGridLayout.cpp +++ b/src/widgets/GraphGridLayout.cpp @@ -103,14 +103,24 @@ Edge routing can be split into: main column selection, rough routing, segment of Transition from source to target row is done using single vertical segment. This is called main column. +A sweep line is used for computing main columns: Blocks and edges are processed as events top to +bottom based off their row (max(start row, end row) for edges). Blocked columns are tracked in a +tree structure which allows searching nearest column with at least last N rows empty. The column +of the starting block is favored for the main column, otherwise the target block's column is chosen +if it is not blocked. If both the source and target columns are blocked, nearest unblocked column +is chosen. An empty column can always be found, in the worst case there are empty columns at the +sides of drawing. If two columns are equally close, the tie is broken based on whether the edge is a +true or false branch. In case of upward edges it is allowed to choose a column on the outside which +is slightly further than nearest empty to reduce the chance of producing tilted figure 8 shaped +crossing between two blocks. + Rough routing creates the path of edge using up to 5 segments using grid coordinates. Due to nodes being placed in a grid. Horizontal segments of edges can't intersect with any nodes. The path for edges is chosen so that it consists of at most 5 segments, typically resulting in sideways U shape or square Z shape. - short vertical segment from node to horizontal line - move to empty column -- vertical segment between starting row and end row, an empty column can always be found, in the -worst case there are empty columns at the sides of drawing +- vertical segment between starting row and end row - horizontal segment to target node column - short vertical segment connecting to target node @@ -118,9 +128,6 @@ There are 3 special cases: - source and target nodes are in the same column with no nodes between - single vertical segment - column bellow stating node is empty - segments 1-3 are merged - column above target node is empty - segments 3-5 are merged -Vertical segment intersection with nodes is prevented using a 2d array marking which vertical -segments are blocked and naively iterating through all rows between start and end at the desired -column. After rough routing segment offsets are calculated relative to their corresponding edge column. This ensures that two segments don't overlap. Segment offsets within each column are assigned greedily From ddefc0663ac2ec157c368bd68db10217877c75d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C4=81rlis=20Se=C5=86ko?= Date: Wed, 10 Aug 2022 14:01:44 +0300 Subject: [PATCH 146/240] Don't leak memory in bb highlighter. --- src/common/BasicBlockHighlighter.cpp | 21 ++++++--------------- src/common/BasicBlockHighlighter.h | 17 +++++++---------- 2 files changed, 13 insertions(+), 25 deletions(-) diff --git a/src/common/BasicBlockHighlighter.cpp b/src/common/BasicBlockHighlighter.cpp index f81b336b..d8270d44 100644 --- a/src/common/BasicBlockHighlighter.cpp +++ b/src/common/BasicBlockHighlighter.cpp @@ -2,21 +2,14 @@ BasicBlockHighlighter::BasicBlockHighlighter() {} -BasicBlockHighlighter::~BasicBlockHighlighter() -{ - for (BasicBlockIt itr = bbMap.begin(); itr != bbMap.end(); ++itr) { - delete itr->second; - } -} - /** * @brief Highlight the basic block at address */ void BasicBlockHighlighter::highlight(RVA address, const QColor &color) { - BasicBlock *block = new BasicBlock; - block->address = address; - block->color = color; + BasicBlock block; + block.address = address; + block.color = color; bbMap[address] = block; } @@ -33,13 +26,11 @@ void BasicBlockHighlighter::clear(RVA address) * * If there is nothing to highlight at specified address, returns nullptr */ -BasicBlock *BasicBlockHighlighter::getBasicBlock(RVA address) +BasicBlockHighlighter::BasicBlock *BasicBlockHighlighter::getBasicBlock(RVA address) { - BasicBlockIt it; - - it = bbMap.find(address); + auto it = bbMap.find(address); if (it != bbMap.end()) { - return it->second; + return &it->second; } return nullptr; diff --git a/src/common/BasicBlockHighlighter.h b/src/common/BasicBlockHighlighter.h index fc84b32a..2e0825e3 100644 --- a/src/common/BasicBlockHighlighter.h +++ b/src/common/BasicBlockHighlighter.h @@ -6,26 +6,23 @@ class BasicBlockHighlighter; #include "Cutter.h" #include -struct BasicBlock -{ - RVA address; - QColor color; -}; - -typedef std::map::iterator BasicBlockIt; - class BasicBlockHighlighter { public: + struct BasicBlock + { + RVA address; + QColor color; + }; + BasicBlockHighlighter(); - ~BasicBlockHighlighter(); void highlight(RVA address, const QColor &color); void clear(RVA address); BasicBlock *getBasicBlock(RVA address); private: - std::map bbMap; + std::map bbMap; }; #endif // BASICBLOCKHIGHLIGHTER_H From c263d4bd1b35882a223f8cda7b3400fddbf92a80 Mon Sep 17 00:00:00 2001 From: billow Date: Thu, 11 Aug 2022 01:18:56 +0800 Subject: [PATCH 147/240] Convert `agcj` command call to the API (#3012) --- rizin | 2 +- src/widgets/CallGraph.cpp | 90 +++++++++++++++++++++++---------------- src/widgets/CallGraph.h | 1 - 3 files changed, 54 insertions(+), 39 deletions(-) diff --git a/rizin b/rizin index 215e4925..a9c59ce1 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 215e49253d3a35e1aae340b7ae8465018254ae87 +Subproject commit a9c59ce1ddc44c498b6a9a02e36989a34f184286 diff --git a/src/widgets/CallGraph.cpp b/src/widgets/CallGraph.cpp index c66a862e..2fbf603d 100644 --- a/src/widgets/CallGraph.cpp +++ b/src/widgets/CallGraph.cpp @@ -53,11 +53,8 @@ void CallGraphView::showExportDialog() void CallGraphView::showAddress(RVA address) { if (global) { - auto addressMappingIt = addressMapping.find(address); - if (addressMappingIt != addressMapping.end()) { - selectBlockWithId(addressMappingIt->second); - showBlock(blocks[addressMappingIt->second]); - } + selectBlockWithId(address); + showBlock(blocks[address]); } else if (address != this->address) { this->address = address; refreshView(); @@ -72,53 +69,72 @@ void CallGraphView::refreshView() SimpleTextGraphView::refreshView(); } +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() { blockContent.clear(); blocks.clear(); - CutterJson nodes = Core()->cmdj(global ? "agCj" : QString("agcj @ %1").arg(address)); + const ut64 from = Core()->getConfigi("graph.from"); + const ut64 to = Core()->getConfigi("graph.to"); + const bool usenames = Core()->getConfigb("graph.json.usenames"); - QHash idMapping; + auto edges = std::unordered_set {}; + auto addFunction = [&](RzAnalysisFunction *fcn) { + GraphLayout::GraphBlock block; + block.entry = fcn->addr; - auto getId = [&](const QString &name) -> uint64_t { - auto nextId = idMapping.size(); - auto &itemId = idMapping[name]; - if (idMapping.size() != nextId) { - itemId = nextId; + auto xrefs = PRzList { rz_analysis_function_get_xrefs_from(fcn), rz_list_free }; + auto calls = std::unordered_set(); + for (const auto &xref : CutterRzList(xrefs.get())) { + const auto x = xref->to; + if (!(xref->type == RZ_ANALYSIS_XREF_TYPE_CALL && calls.find(x) == calls.end())) { + continue; + } + calls.insert(x); + block.edges.emplace_back(x); + edges.insert(x); } - return itemId; + + QString name = usenames ? fcn->name : RzAddressString(fcn->addr); + addBlock(std::move(block), name, fcn->addr); }; - for (CutterJson block : nodes) { - QString name = block["name"].toString(); - - auto edges = block["imports"]; - GraphLayout::GraphBlock layoutBlock; - layoutBlock.entry = getId(name); - for (auto edge : edges) { - auto targetName = edge.toString(); - auto targetId = getId(targetName); - layoutBlock.edges.emplace_back(targetId); + if (global) { + for (const auto &fcn : CutterRzList(Core()->core()->analysis->fcns)) { + if (!isBetween(from, fcn->addr, to)) { + continue; + } + addFunction(fcn); + } + } else { + const auto &fcn = Core()->functionIn(address); + if (fcn) { + addFunction(fcn); } - - // it would be good if address came directly from json instead of having to lookup by name - addBlock(std::move(layoutBlock), name, Core()->num(name)); } - for (auto it = idMapping.begin(), end = idMapping.end(); it != end; ++it) { - if (blocks.find(it.value()) == blocks.end()) { - GraphLayout::GraphBlock block; - block.entry = it.value(); - addBlock(std::move(block), it.key(), Core()->num(it.key())); + + for (const auto &x : edges) { + if (blockContent.find(x) != blockContent.end()) { + continue; } + GraphLayout::GraphBlock block; + block.entry = x; + QString flagName = Core()->flagAt(x); + QString name = usenames + ? (!flagName.isEmpty() ? flagName : QString("unk.%0").arg(RzAddressString(x))) + : RzAddressString(x); + addBlock(std::move(block), name, x); } if (blockContent.empty() && !global) { - addBlock({}, RzAddressString(address), address); - } - - addressMapping.clear(); - for (auto &it : blockContent) { - addressMapping[it.second.address] = it.first; + const auto name = RzAddressString(address); + addBlock({}, name, address); } computeGraphPlacement(); diff --git a/src/widgets/CallGraph.h b/src/widgets/CallGraph.h index 8085fdcf..2d348266 100644 --- a/src/widgets/CallGraph.h +++ b/src/widgets/CallGraph.h @@ -22,7 +22,6 @@ public: protected: bool global; ///< is this a global or function callgraph RVA address = RVA_INVALID; ///< function address if this is not a global callgraph - std::unordered_map addressMapping; ///< mapping from addresses to block id void loadCurrentGraph() override; void restoreCurrentBlock() override; From a5b0dd3ed204cbb24fa1b6b95e030fa89aa0fe53 Mon Sep 17 00:00:00 2001 From: billow Date: Thu, 11 Aug 2022 18:05:14 +0800 Subject: [PATCH 148/240] Convert commands(`agJ`, `anj`, `pi`) to rizin APIs (#3005) --- src/common/Configuration.cpp | 1 - src/common/TempConfig.h | 1 - src/core/Cutter.cpp | 66 +++++------- src/core/Cutter.h | 11 +- src/menus/DisassemblyContextMenu.cpp | 74 ++++++------- src/widgets/DisassemblerGraphView.cpp | 143 ++++++++++++++------------ 6 files changed, 140 insertions(+), 156 deletions(-) diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 25d5907a..7fc76715 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -201,7 +201,6 @@ void Configuration::resetAll() { // Don't reset all rizin vars, that currently breaks a bunch of stuff. // settingsFile.remove()+loadInitials() should reset all settings configurable using Cutter GUI. - // Core()->cmdRaw("e-"); Core()->setSettings(); // Delete the file so no extra configuration is in it. diff --git a/src/common/TempConfig.h b/src/common/TempConfig.h index ba9b6f1e..a3c2239d 100644 --- a/src/common/TempConfig.h +++ b/src/common/TempConfig.h @@ -19,7 +19,6 @@ * { * TempConfig tempConfig; * tempConfig.set("asm.arch", "x86").set("asm.comments", false); - * return Core()->cmdRaw("pd"); * // config automatically restored at the end of scope * } * \endcode diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 78e82ec4..5e25c9dc 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -777,34 +777,32 @@ void CutterCore::delFlag(const QString &name) emit flagsChanged(); } +PRzAnalysisBytes CutterCore::getRzAnalysisBytesSingle(RVA addr) +{ + CORE_LOCK(); + ut8 buf[128]; + rz_io_read_at(core->io, addr, buf, sizeof(buf)); + std::unique_ptr vec { + returnAtSeek( + [&]() { return rz_core_analysis_bytes(core, buf, sizeof(buf), 1); }, addr), + rz_pvector_free + }; + auto ab = vec && rz_pvector_len(vec.get()) > 0 + ? reinterpret_cast(rz_pvector_pop_front(vec.get())) + : nullptr; + return { ab, rz_analysis_bytes_free }; +} + QString CutterCore::getInstructionBytes(RVA addr) { - auto ret = (char *)Core()->returnAtSeek( - [&]() { - CORE_LOCK(); - RzPVector *vec = rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); - auto *ab = static_cast(rz_pvector_head(vec)); - char *str = strdup(ab->bytes); - rz_pvector_free(vec); - return str; - }, - addr); - return fromOwnedCharPtr(ret); + auto ab = getRzAnalysisBytesSingle(addr); + return ab ? ab->bytes : ""; } QString CutterCore::getInstructionOpcode(RVA addr) { - auto ret = (char *)Core()->returnAtSeek( - [&]() { - CORE_LOCK(); - RzPVector *vec = rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); - auto *ab = static_cast(rz_pvector_head(vec)); - char *str = strdup(ab->opcode); - rz_pvector_free(vec); - return str; - }, - addr); - return fromOwnedCharPtr(ret); + auto ab = getRzAnalysisBytesSingle(addr); + return ab ? ab->opcode : ""; } void CutterCore::editInstruction(RVA addr, const QString &inst, bool fillWithNops) @@ -910,7 +908,7 @@ QString CutterCore::getString(RVA addr, uint64_t len, RzStrEnc encoding, bool es opt.length = len; opt.encoding = encoding; opt.escape_nl = escape_nl; - char *s = (char *)returnAtSeek([&]() { return rz_str_stringify_raw_buffer(&opt, NULL); }, addr); + char *s = returnAtSeek([&]() { return rz_str_stringify_raw_buffer(&opt, NULL); }, addr); return fromOwnedCharPtr(s); } @@ -1086,11 +1084,11 @@ RVA CutterCore::prevOpAddr(RVA startAddr, int count) RVA CutterCore::nextOpAddr(RVA startAddr, int count) { CORE_LOCK(); - auto vec = reinterpret_cast(returnAtSeek( + auto vec = returnAtSeek( [&]() { return rz_core_analysis_bytes(core, core->block, (int)core->blocksize, count + 1); }, - startAddr)); + startAddr); RVA addr = startAddr + 1; if (!vec) { return addr; @@ -1326,7 +1324,8 @@ QString CutterCore::disassemble(const QByteArray &data) QString CutterCore::disassembleSingleInstruction(RVA addr) { - return cmdRawAt("pi 1", addr).simplified(); + auto ab = getRzAnalysisBytesSingle(addr); + return QString(ab->disasm).simplified(); } RzAnalysisFunction *CutterCore::functionIn(ut64 addr) @@ -1430,19 +1429,8 @@ void CutterCore::createFunctionAt(RVA addr, QString name) RVA CutterCore::getOffsetJump(RVA addr) { - auto rva = (RVA *)Core()->returnAtSeek( - [&]() { - CORE_LOCK(); - RzPVector *vec = rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); - auto *ab = static_cast(rz_pvector_head(vec)); - RVA *rva = new RVA(ab->op->jump); - rz_pvector_free(vec); - return rva; - }, - addr); - RVA ret = *rva; - delete rva; - return ret; + auto ab = getRzAnalysisBytesSingle(addr); + return ab && ab->op ? ab->op->jump : RVA_INVALID; } QList CutterCore::getDecompilers() diff --git a/src/core/Cutter.h b/src/core/Cutter.h index dd042109..b92167e3 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -32,6 +32,7 @@ class RizinTaskDialog; #include "common/Helpers.h" #include +#include #define Core() (CutterCore::instance()) @@ -60,6 +61,8 @@ struct CUTTER_EXPORT RegisterRef QString name; }; +using PRzAnalysisBytes = std::unique_ptr; + class CUTTER_EXPORT CutterCore : public QObject { Q_OBJECT @@ -153,7 +156,7 @@ public: return cmdRawAt(str.toUtf8().constData(), address); } - void applyAtSeek(std::function fn, RVA address) + void applyAtSeek(const std::function &fn, RVA address) { RVA oldOffset = getOffset(); seekSilent(address); @@ -161,11 +164,12 @@ public: seekSilent(oldOffset); } - void *returnAtSeek(std::function fn, RVA address) + template + T returnAtSeek(const std::function &fn, RVA address) { RVA oldOffset = getOffset(); seekSilent(address); - void *ret = fn(); + T ret = fn(); seekSilent(oldOffset); return ret; } @@ -273,6 +277,7 @@ public: void triggerFlagsChanged(); /* Edition functions */ + PRzAnalysisBytes getRzAnalysisBytesSingle(RVA addr); QString getInstructionBytes(RVA addr); QString getInstructionOpcode(RVA addr); void editInstruction(RVA addr, const QString &inst, bool fillWithNops = false); diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index f08b8c5e..ddbfea65 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -313,34 +313,34 @@ void DisassemblyContextMenu::addDebugMenu() QVector DisassemblyContextMenu::getThingUsedHere(RVA offset) { - QVector result; - const CutterJson array = Core()->cmdj("anj @ " + QString::number(offset)); - result.reserve(array.size()); - for (const auto &thing : array) { - auto obj = thing; - RVA offset = obj["offset"].toRVA(); - QString name; - - // If real names display is enabled, show flag's real name instead of full flag name - if (Config()->getConfigBool("asm.flags.real") && obj["realname"].valid()) { - name = obj["realname"].toString(); - } else { - name = obj["name"].toString(); - } - - QString typeString = obj["type"].toString(); - ThingUsedHere::Type type = ThingUsedHere::Type::Address; - if (typeString == "var") { - type = ThingUsedHere::Type::Var; - } else if (typeString == "flag") { - type = ThingUsedHere::Type::Flag; - } else if (typeString == "function") { - type = ThingUsedHere::Type::Function; - } else if (typeString == "address") { - type = ThingUsedHere::Type::Address; - } - result.push_back(ThingUsedHere { name, offset, type }); + RzCoreLocked core(Core()); + auto p = std::unique_ptr { + rz_core_analysis_name(core, offset), rz_core_analysis_name_free + }; + if (!p) { + return {}; } + + QVector result; + ThingUsedHere th; + th.offset = p->offset; + th.name = Config()->getConfigBool("asm.flags.real") && p->realname ? p->realname : p->name; + switch (p->type) { + case RZ_CORE_ANALYSIS_NAME_TYPE_FLAG: + th.type = ThingUsedHere::Type::Flag; + break; + case RZ_CORE_ANALYSIS_NAME_TYPE_FUNCTION: + th.type = ThingUsedHere::Type::Function; + break; + case RZ_CORE_ANALYSIS_NAME_TYPE_VAR: + th.type = ThingUsedHere::Type::Var; + break; + case RZ_CORE_ANALYSIS_NAME_TYPE_ADDRESS: + default: + th.type = ThingUsedHere::Type::Address; + break; + } + result.push_back(th); return result; } @@ -482,13 +482,7 @@ void DisassemblyContextMenu::setupRenaming() void DisassemblyContextMenu::aboutToShowSlot() { // check if set immediate base menu makes sense - RzPVector *vec = (RzPVector *)Core()->returnAtSeek( - [&]() { - RzCoreLocked core(Core()); - return rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); - }, - offset); - auto *ab = static_cast(rz_pvector_head(vec)); + auto ab = Core()->getRzAnalysisBytesSingle(offset); bool immBase = ab && ab->op && (ab->op->val || ab->op->ptr); setBaseMenu->menuAction()->setVisible(immBase); @@ -514,7 +508,6 @@ void DisassemblyContextMenu::aboutToShowSlot() } } } - rz_pvector_free(vec); if (memBaseReg.isEmpty()) { // hide structure offset menu @@ -727,22 +720,13 @@ void DisassemblyContextMenu::on_actionNopInstruction_triggered() void DisassemblyContextMenu::showReverseJmpQuery() { actionJmpReverse.setVisible(false); - RzCoreLocked core(Core()); - auto vec = reinterpret_cast(Core()->returnAtSeek( - [&]() { return rz_core_analysis_bytes(core, core->block, (int)core->blocksize, 1); }, - offset)); - if (!vec) { - return; - } - auto ab = reinterpret_cast(rz_pvector_head(vec)); + auto ab = Core()->getRzAnalysisBytesSingle(offset); if (!(ab && ab->op)) { - rz_pvector_free(vec); return; } if (ab->op->type == RZ_ANALYSIS_OP_TYPE_CJMP) { actionJmpReverse.setVisible(true); } - rz_pvector_free(vec); } void DisassemblyContextMenu::on_actionJmpReverse_triggered() diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index 09dacdd2..63bf6832 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -109,14 +109,14 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable *se if (c.isValid()) { bbh->highlight(currBlockEntry, c); } - Config()->colorsUpdated(); + emit Config()->colorsUpdated(); }); actionUnhighlight.setText(tr("Unhighlight block")); connect(&actionUnhighlight, &QAction::triggered, this, [this]() { auto bbh = Core()->getBBHighlighter(); bbh->clear(blockForAddress(this->seekable->getOffset())->entry); - Config()->colorsUpdated(); + emit Config()->colorsUpdated(); }); QAction *highlightBI = new QAction(this); @@ -162,9 +162,8 @@ void DisassemblerGraphView::connectSeekChanged(bool disconn) DisassemblerGraphView::~DisassemblerGraphView() { - for (QShortcut *shortcut : shortcuts) { - delete shortcut; - } + qDeleteAll(shortcuts); + shortcuts.clear(); } void DisassemblerGraphView::refreshView() @@ -182,13 +181,6 @@ void DisassemblerGraphView::loadCurrentGraph() .set("asm.lines", false) .set("asm.lines.fcn", false); - CutterJson functions; - RzAnalysisFunction *fcn = Core()->functionIn(seekable->getOffset()); - if (fcn) { - currentFcnAddr = fcn->addr; - functions = Core()->cmdj("agJ " + RzAddressString(fcn->addr)); - } - disassembly_blocks.clear(); blocks.clear(); @@ -197,7 +189,20 @@ void DisassemblerGraphView::loadCurrentGraph() highlight_token = nullptr; } - emptyGraph = !functions.size(); + RzAnalysisFunction *fcn = Core()->functionIn(seekable->getOffset()); + + windowTitle = tr("Graph"); + if (fcn && RZ_STR_ISNOTEMPTY(fcn->name)) { + std::unique_ptr fcnName { + rz_str_escape_utf8_for_json(fcn->name, -1), std::free + }; + windowTitle += QString("(%0)").arg(fcnName.get()); + } else { + windowTitle += "(Empty)"; + } + emit nameChanged(windowTitle); + + emptyGraph = !fcn; if (emptyGraph) { // If there's no function to print, just add a message if (!emptyText) { @@ -213,31 +218,20 @@ void DisassemblerGraphView::loadCurrentGraph() } // Refresh global "empty graph" variable so other widget know there is nothing to show here Core()->setGraphEmpty(emptyGraph); + setEntry(fcn ? fcn->addr : RVA_INVALID); - CutterJson func = functions.first(); - - windowTitle = tr("Graph"); - QString funcName = func["name"].toString().trimmed(); - if (emptyGraph) { - windowTitle += " (Empty)"; - } else if (!funcName.isEmpty()) { - windowTitle += " (" + funcName + ")"; + if (!fcn) { + return; } - emit nameChanged(windowTitle); - RVA entry = func["offset"].toRVA(); - - setEntry(entry); - for (CutterJson block : func["blocks"]) { - RVA block_entry = block["offset"].toRVA(); - RVA block_size = block["size"].toRVA(); - RVA block_fail = block["fail"].toRVA(); - RVA block_jump = block["jump"].toRVA(); + for (const auto &bbi : CutterRzList(fcn->bbs)) { + RVA bbiFail = bbi->fail; + RVA bbiJump = bbi->jump; DisassemblyBlock db; GraphBlock gb; - gb.entry = block_entry; - db.entry = block_entry; + gb.entry = bbi->addr; + db.entry = bbi->addr; if (Config()->getGraphBlockEntryOffset()) { // QColor(0,0,0,0) is transparent db.header_text = Text("[" + RzAddressString(db.entry) + "]", ConfigColor("offset"), @@ -245,50 +239,69 @@ void DisassemblerGraphView::loadCurrentGraph() } db.true_path = RVA_INVALID; db.false_path = RVA_INVALID; - if (block_fail) { - db.false_path = block_fail; - gb.edges.emplace_back(block_fail); + if (bbiFail) { + db.false_path = bbiFail; + gb.edges.emplace_back(bbiFail); } - if (block_jump) { - if (block_fail) { - db.true_path = block_jump; + if (bbiJump) { + if (bbiFail) { + db.true_path = bbiJump; } - gb.edges.emplace_back(block_jump); + gb.edges.emplace_back(bbiJump); } - CutterJson switchOp = block["switchop"]; - if (switchOp.size()) { - for (CutterJson caseOp : switchOp["cases"]) { - RVA caseJump = caseOp["jump"].toRVA(); - if (caseJump == RVA_INVALID) { + RzAnalysisSwitchOp *switchOp = bbi->switch_op; + if (switchOp) { + for (const auto &caseOp : CutterRzList(switchOp->cases)) { + if (caseOp->jump == RVA_INVALID) { continue; } - gb.edges.emplace_back(caseJump); + gb.edges.emplace_back(caseOp->jump); } } - CutterJson opArray = block["ops"]; - CutterJson::iterator iterator = opArray.begin(); - while (iterator != opArray.end()) { - CutterJson op = *iterator; - Instr i; - i.addr = op["offset"].toUt64(); + RzCoreLocked core(Core()); + std::unique_ptr buf { new ut8[bbi->size] }; + if (!buf) { + break; + } + rz_io_read_at(core->io, bbi->addr, buf.get(), (int)bbi->size); - ++iterator; + std::unique_ptr vec { + rz_pvector_new(reinterpret_cast(rz_analysis_disasm_text_free)), + rz_pvector_free + }; + if (!vec) { + break; + } - if (iterator != opArray.end()) { + RzCoreDisasmOptions options = {}; + options.vec = vec.get(); + options.cbytes = 1; + rz_core_print_disasm(core, bbi->addr, buf.get(), (int)bbi->size, (int)bbi->size, NULL, + &options); + + auto vecVisitor = CutterPVector(vec.get()); + auto iter = vecVisitor.begin(); + while (iter != vecVisitor.end()) { + RzAnalysisDisasmText *op = *iter; + Instr instr; + instr.addr = op->offset; + + ++iter; + if (iter != vecVisitor.end()) { // get instruction size from distance to next instruction ... - RVA nextOffset = (*iterator)["offset"].toRVA(); - i.size = nextOffset - i.addr; + RVA nextOffset = (*iter)->offset; + instr.size = nextOffset - instr.addr; } else { // or to the end of the block. - i.size = (block_entry + block_size) - i.addr; + instr.size = (bbi->addr + bbi->size) - instr.addr; } QTextDocument textDoc; - textDoc.setHtml(CutterCore::ansiEscapeToHtml(op["text"].toString())); + textDoc.setHtml(CutterCore::ansiEscapeToHtml(op->text)); - i.plainText = textDoc.toPlainText(); + instr.plainText = textDoc.toPlainText(); RichTextPainter::List richText = RichTextPainter::fromTextDocument(textDoc); // Colors::colorizeAssembly(richText, textDoc.toPlainText(), 0); @@ -296,23 +309,19 @@ void DisassemblerGraphView::loadCurrentGraph() bool cropped; int blockLength = Config()->getGraphBlockMaxChars() + Core()->getConfigb("asm.bytes") * 24 + Core()->getConfigb("asm.emu") * 10; - i.text = Text(RichTextPainter::cropped(richText, blockLength, "...", &cropped)); + instr.text = Text(RichTextPainter::cropped(richText, blockLength, "...", &cropped)); if (cropped) - i.fullText = richText; + instr.fullText = richText; else - i.fullText = Text(); - db.instrs.push_back(i); + instr.fullText = Text(); + db.instrs.push_back(instr); } disassembly_blocks[db.entry] = db; prepareGraphNode(gb); - addBlock(gb); } cleanupEdges(blocks); - - if (func["blocks"].size()) { - computeGraphPlacement(); - } + computeGraphPlacement(); } DisassemblerGraphView::EdgeConfigurationMapping DisassemblerGraphView::getEdgeConfigurations() From 6b7b1d1450d0d47a8dd165005b5e4f872e04cb35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C4=81rlis=20Se=C5=86ko?= Date: Thu, 11 Aug 2022 10:19:18 +0300 Subject: [PATCH 149/240] Do not check "Built from source" in bug report template by default. --- src/common/BugReporting.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/BugReporting.cpp b/src/common/BugReporting.cpp index 18aa36ef..95da855f 100644 --- a/src/common/BugReporting.cpp +++ b/src/common/BugReporting.cpp @@ -23,7 +23,7 @@ void openIssue() url = "https://github.com/rizinorg/cutter/issues/new?&body=**Environment information**\n* " "Operating System: " + osInfo + "\n* Cutter version: " + CUTTER_VERSION_FULL + "\n* Obtained from:\n" - + " - [x] Built from source\n - [ ] Downloaded release from Cutter website or GitHub " + + " - [ ] Built from source\n - [ ] Downloaded release from Cutter website or GitHub " "\n" " - [ ] Distribution repository\n* File format: " + format + "\n * Arch: " + arch + "\n * Type: " + type From 617c79f97653c52f7d4d36fcb4e5f0a86c94723c Mon Sep 17 00:00:00 2001 From: billow Date: Thu, 11 Aug 2022 20:46:18 +0800 Subject: [PATCH 150/240] Convert `pdsf` to API (#3010) * convert `pdsf` * remove unused - `CutterCore.opcodes` - `cmdList` --- src/common/Highlighter.cpp | 9 --------- src/core/Cutter.cpp | 4 +--- src/core/Cutter.h | 8 +------- src/core/MainWindow.cpp | 12 +++++++++--- src/widgets/FunctionsWidget.cpp | 16 +++++++++++++--- 5 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/common/Highlighter.cpp b/src/common/Highlighter.cpp index 5431a398..03a9e3bf 100644 --- a/src/common/Highlighter.cpp +++ b/src/common/Highlighter.cpp @@ -9,15 +9,6 @@ Highlighter::Highlighter(QTextDocument *parent) : QSyntaxHighlighter(parent) core = Core(); - keywordFormat.setForeground(QColor(65, 131, 215)); - - for (const QString &pattern : this->core->opcodes) { - rule.pattern.setPattern("\\b" + pattern + "\\b"); - rule.pattern.setPatternOptions(QRegularExpression::CaseInsensitiveOption); - rule.format = keywordFormat; - highlightingRules.append(rule); - } - regFormat.setForeground(QColor(236, 100, 75)); for (const QString &pattern : this->core->regs) { diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 5e25c9dc..c69c4df5 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -2944,11 +2944,9 @@ bool CutterCore::isGraphEmpty() return emptyGraph; } -void CutterCore::getOpcodes() +void CutterCore::getRegs() { CORE_LOCK(); - this->opcodes = cmdList("?O"); - this->regs = {}; const RzList *rs = rz_reg_get_list(getReg(), RZ_REG_TYPE_ANY); if (!rs) { diff --git a/src/core/Cutter.h b/src/core/Cutter.h index b92167e3..01bcc24d 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -188,11 +188,6 @@ public: CutterJson cmdj(const char *str); CutterJson cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); } CutterJson cmdjAt(const char *str, RVA address); - QStringList cmdList(const char *str) - { - return cmd(str).split(QLatin1Char('\n'), CUTTER_QT_SKIP_EMPTY_PARTS); - } - QStringList cmdList(const QString &str) { return cmdList(str.toUtf8().constData()); } QString cmdTask(const QString &str); CutterJson cmdjTask(const QString &str); /** @@ -595,8 +590,7 @@ public: void setGraphEmpty(bool empty); bool isGraphEmpty(); - void getOpcodes(); - QList opcodes; + void getRegs(); QList regs; void setSettings(); diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index 339884cc..bfd3434d 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -637,7 +637,7 @@ bool MainWindow::openProject(const QString &file) void MainWindow::finalizeOpen() { - core->getOpcodes(); + core->getRegs(); core->updateSeek(); refreshAll(); // Add fortune message @@ -1762,10 +1762,16 @@ void MainWindow::on_actionExport_as_code_triggered() QTextStream fileOut(&file); auto ps = core->seekTemp(0); auto rc = core->core(); + const auto size = static_cast(rz_io_fd_size(rc->io, rc->file->fd)); + auto buffer = std::vector(size); + if (!rz_io_read_at(Core()->core()->io, 0, buffer.data(), size)) { + return; + } + std::unique_ptr string { dialog.selectedNameFilter() != instructionsInComments - ? rz_lang_byte_array(rc->block, rc->blocksize, typMap[dialog.selectedNameFilter()]) - : rz_core_print_bytes_with_inst(rc, rc->block, rc->offset, rc->blocksize), + ? rz_lang_byte_array(buffer.data(), size, typMap[dialog.selectedNameFilter()]) + : rz_core_print_bytes_with_inst(rc, buffer.data(), 0, size), free }; fileOut << string.get(); diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index b59cfb34..864780c4 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -231,7 +231,17 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const QStringList disasmPreview = Core()->getDisassemblyPreview(function.offset, kMaxTooltipDisasmPreviewLines); - const QStringList &summary = Core()->cmdList(QString("pdsf @ %1").arg(function.offset)); + QStringList summary {}; + { + auto seeker = Core()->seekTemp(function.offset); + auto strings = std::unique_ptr { + 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); + } + const QFont &fnt = Config()->getFont(); QFontMetrics fm { fnt }; @@ -245,7 +255,7 @@ QVariant FunctionModel::data(const QModelIndex &index, int role) const } } if (disasmPreview.isEmpty() && highlights.isEmpty()) - return QVariant(); + return {}; QString toolTipContent = QString("
contains(function.offset); default: - return QVariant(); + return {}; } } From 39bf5c6429d199a9a18e16cfb1cbd7e285ca79c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C4=81rlis=20Se=C5=86ko?= Date: Thu, 11 Aug 2022 11:01:56 +0300 Subject: [PATCH 151/240] Don't try to load files with wrong extension as native plugins. #2626 --- src/plugins/PluginManager.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/plugins/PluginManager.cpp b/src/plugins/PluginManager.cpp index ac9c6104..6f6a5aa5 100644 --- a/src/plugins/PluginManager.cpp +++ b/src/plugins/PluginManager.cpp @@ -133,6 +133,10 @@ QString PluginManager::getUserPluginsDirectory() const void PluginManager::loadNativePlugins(const QDir &directory) { for (const QString &fileName : directory.entryList(QDir::Files)) { + if (!QLibrary::isLibrary(fileName)) { + // Reduce amount of warnings, by not attempting files which are obviously not plugins + continue; + } QPluginLoader pluginLoader(directory.absoluteFilePath(fileName)); QObject *plugin = pluginLoader.instance(); if (!plugin) { From 41c4857ed9c1fb531b86fa8d66f6bb9c8398f6b1 Mon Sep 17 00:00:00 2001 From: karliss Date: Sat, 13 Aug 2022 23:12:57 +0300 Subject: [PATCH 152/240] Introduce some helpers to deal with rizin C API more cleanly. (#3020) --- src/CMakeLists.txt | 2 + src/common/DecompilerHighlighter.cpp | 3 +- src/core/Cutter.cpp | 80 ++++++------- src/core/Cutter.h | 47 ++++---- src/core/CutterCommon.h | 98 +--------------- src/core/MainWindow.cpp | 8 +- src/core/RizinCpp.cpp | 2 + src/core/RizinCpp.h | 154 ++++++++++++++++++++++++++ src/dialogs/EditMethodDialog.cpp | 6 +- src/menus/DisassemblyContextMenu.cpp | 5 +- src/widgets/CallGraph.cpp | 3 +- src/widgets/DisassemblerGraphView.cpp | 10 +- src/widgets/FunctionsWidget.cpp | 8 +- src/widgets/VisualNavbar.cpp | 8 +- src/widgets/VisualNavbar.h | 2 +- 15 files changed, 238 insertions(+), 198 deletions(-) create mode 100644 src/core/RizinCpp.cpp create mode 100644 src/core/RizinCpp.h 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; From 756850ae27c1ca34b4c9d2d1a81c69d9c79409b9 Mon Sep 17 00:00:00 2001 From: billow Date: Sun, 14 Aug 2022 17:10:18 +0800 Subject: [PATCH 153/240] Convert cmds {`.`, `afv[WR]j`} (#3017) * remove `asyncCmd` `asyncCmdEsil`, `cmdjTask`, `cmdEsil`, `cmdjAt` * convert `afv[WR]j` --- rizin | 2 +- src/common/RunScriptTask.cpp | 5 +- src/core/Cutter.cpp | 120 ++++++++++------------------------- src/core/Cutter.h | 41 +----------- src/dialogs/AboutDialog.cpp | 2 - 5 files changed, 41 insertions(+), 129 deletions(-) diff --git a/rizin b/rizin index a9c59ce1..32ef1713 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit a9c59ce1ddc44c498b6a9a02e36989a34f184286 +Subproject commit 32ef171354e2fde6194a354a1a350df357c08afc diff --git a/src/common/RunScriptTask.cpp b/src/common/RunScriptTask.cpp index 7bac2d99..ca830b1a 100644 --- a/src/common/RunScriptTask.cpp +++ b/src/common/RunScriptTask.cpp @@ -16,7 +16,10 @@ void RunScriptTask::runTask() { if (!this->fileName.isNull()) { log(tr("Executing script...")); - Core()->cmdTask(". " + this->fileName); + Core()->functionTask([&](RzCore *core) { + rz_core_run_script(core, this->fileName.toUtf8().constData()); + return nullptr; + }); if (isInterrupted()) { return; } diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index ac8634b1..513806ff 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -430,48 +430,6 @@ bool CutterCore::isDebugTaskInProgress() return false; } -bool CutterCore::asyncCmdEsil(const char *command, QSharedPointer &task) -{ - asyncCmd(command, task); - - if (task.isNull()) { - return false; - } - - connect(task.data(), &RizinCmdTask::finished, task.data(), [this, task]() { - QString res = qobject_cast(task.data())->getResult(); - - if (res.contains(QStringLiteral("[ESIL] Stopped execution in an invalid instruction"))) { - msgBox.showMessage("Stopped when attempted to run an invalid instruction. You can " - "disable this in Preferences"); - } - }); - - return true; -} - -bool CutterCore::asyncCmd(const char *str, QSharedPointer &task) -{ - if (!task.isNull()) { - return false; - } - - CORE_LOCK(); - - RVA offset = core->offset; - - task = QSharedPointer(new RizinCmdTask(str, true)); - connect(task.data(), &RizinTask::finished, task.data(), [this, offset, task]() { - CORE_LOCK(); - - if (offset != core->offset) { - updateSeek(); - } - }); - - return true; -} - bool CutterCore::asyncTask(std::function fcn, QSharedPointer &task) { if (!task.isNull()) { @@ -492,6 +450,13 @@ bool CutterCore::asyncTask(std::function fcn, QSharedPointer fcn) +{ + auto task = std::unique_ptr(new RizinFunctionTask(std::move(fcn), true)); + task->startTask(); + task->joinTask(); +} + QString CutterCore::cmdRawAt(const char *cmd, RVA address) { QString res; @@ -534,18 +499,6 @@ CutterJson CutterCore::cmdj(const char *str) return parseJson(res, str); } -CutterJson CutterCore::cmdjAt(const char *str, RVA address) -{ - CutterJson res; - RVA oldOffset = getOffset(); - seekSilent(address); - - res = cmdj(str); - - seekSilent(oldOffset); - return res; -} - QString CutterCore::cmdTask(const QString &str) { RizinCmdTask task(str); @@ -554,14 +507,6 @@ QString CutterCore::cmdTask(const QString &str) return task.getResult(); } -CutterJson CutterCore::cmdjTask(const QString &str) -{ - RizinCmdTask task(str); - task.startTask(); - task.joinTask(); - return task.getResultJson(); -} - CutterJson CutterCore::parseJson(char *res, const char *cmd) { if (!res) { @@ -1393,16 +1338,6 @@ QString CutterCore::flagAt(RVA addr) return core->flags->realnames && f->realname ? f->realname : f->name; } -void CutterCore::cmdEsil(const char *command) -{ - // use cmd and not cmdRaw because of unexpected commands - QString res = cmd(command); - if (res.contains(QStringLiteral("[ESIL] Stopped execution in an invalid instruction"))) { - msgBox.showMessage("Stopped when attempted to run an invalid instruction. You can disable " - "this in Preferences"); - } -} - void CutterCore::createFunctionAt(RVA addr) { createFunctionAt(addr, ""); @@ -4027,22 +3962,35 @@ QList CutterCore::getAllSearch(QString searchFor, QString spa QList CutterCore::getXRefsForVariable(QString variableName, bool findWrites, RVA offset) { + CORE_LOCK(); + auto fcn = functionIn(offset); + if (!fcn) { + return {}; + } + const auto typ = + findWrites ? RZ_ANALYSIS_VAR_ACCESS_TYPE_WRITE : RZ_ANALYSIS_VAR_ACCESS_TYPE_READ; QList xrefList = QList(); - for (CutterJson xrefObject : cmdjAt(findWrites ? "afvWj" : "afvRj", offset)) { - QString name = xrefObject[RJsonKey::name].toString(); - if (name == variableName) { - for (CutterJson address : xrefObject[RJsonKey::addrs]) { - XrefDescription xref; - RVA addr = address.toRVA(); - xref.from = addr; - xref.to = addr; - if (findWrites) { - xref.from_str = RzAddressString(addr); - } else { - xref.to_str = RzAddressString(addr); - } - xrefList << xref; + RzList *vars = rz_analysis_var_all_list(core->analysis, fcn); + for (const auto &v : CutterRzList(vars)) { + if (variableName != v->name) { + continue; + } + RzAnalysisVarAccess *acc; + CutterRzVectorForeach(&v->accesses, acc, RzAnalysisVarAccess) + { + if (!(acc->type & typ)) { + continue; } + XrefDescription xref; + RVA addr = fcn->addr + acc->offset; + xref.from = addr; + xref.to = addr; + if (findWrites) { + xref.from_str = RzAddressString(addr); + } else { + xref.to_str = RzAddressString(addr); + } + xrefList << xref; } } return xrefList; diff --git a/src/core/Cutter.h b/src/core/Cutter.h index c9b92636..7d8aa098 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -98,21 +98,6 @@ public: */ QString cmd(const char *str); QString cmd(const QString &str) { return cmd(str.toUtf8().constData()); } - /** - * @brief send a command to Rizin asynchronously - * @param str the command you want to execute - * @param task a shared pointer that will be returned with the Rizin command task - * @note connect to the &RizinTask::finished signal to add your own logic once - * the command is finished. Use task->getResult()/getResultJson() for the - * return value. - * Once you have setup connections you can start the task with task->startTask() - * If you want to seek to an address, you should use CutterCore::seek. - */ - bool asyncCmd(const char *str, QSharedPointer &task); - bool asyncCmd(const QString &str, QSharedPointer &task) - { - return asyncCmd(str.toUtf8().constData(), task); - } /** * @brief send a task to Rizin @@ -120,6 +105,7 @@ public: * @return execute successful? */ bool asyncTask(std::function fcn, QSharedPointer &task); + void functionTask(std::function fcn); /** * @brief Execute a Rizin command \a cmd. By nature, the API @@ -188,31 +174,8 @@ public: CutterJson cmdj(const char *str); CutterJson cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); } - CutterJson cmdjAt(const char *str, RVA address); QString cmdTask(const QString &str); - CutterJson cmdjTask(const QString &str); - /** - * @brief send a command to Rizin and check for ESIL errors - * @param command the command you want to execute - * @note If you want to seek to an address, you should use CutterCore::seek. - */ - void cmdEsil(const char *command); - void cmdEsil(const QString &command) { cmdEsil(command.toUtf8().constData()); } - /** - * @brief send a command to Rizin and check for ESIL errors - * @param command the command you want to execute - * @param task a shared pointer that will be returned with the Rizin command task - * @note connect to the &RizinTask::finished signal to add your own logic once - * the command is finished. Use task->getResult()/getResultJson() for the - * return value. - * Once you have setup connections you can start the task with task->startTask() - * If you want to seek to an address, you should use CutterCore::seek. - */ - bool asyncCmdEsil(const char *command, QSharedPointer &task); - bool asyncCmdEsil(const QString &command, QSharedPointer &task) - { - return asyncCmdEsil(command.toUtf8().constData(), task); - } + QString getRizinVersionReadable(const char *program = nullptr); QString getVersionInformation(); diff --git a/src/dialogs/AboutDialog.cpp b/src/dialogs/AboutDialog.cpp index d60a5566..aaca9b47 100644 --- a/src/dialogs/AboutDialog.cpp +++ b/src/dialogs/AboutDialog.cpp @@ -1,4 +1,3 @@ -#include "rz_version.h" #include "core/Cutter.h" #include "AboutDialog.h" @@ -7,7 +6,6 @@ #include "common/Configuration.h" #include "common/BugReporting.h" - #include #include #include From 550c416c0477a1eeb13ccc97a05ee445fe52149f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C4=81rlis=20Se=C5=86ko?= Date: Fri, 12 Aug 2022 16:53:43 +0300 Subject: [PATCH 154/240] Don't refresh graph breakpoints during redraw. --- src/widgets/DisassemblerGraphView.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index fbd5ae39..008e8fd5 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -170,6 +170,7 @@ void DisassemblerGraphView::refreshView() { CutterGraphView::refreshView(); loadCurrentGraph(); + breakpoints = Core()->getBreakpointsAddresses(); emit viewRefreshed(); } @@ -370,8 +371,6 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block, p.setFont(Config()->getFont()); p.drawRect(blockRect); - breakpoints = Core()->getBreakpointsAddresses(); - // Render node DisassemblyBlock &db = disassembly_blocks[block.entry]; bool block_selected = false; From ee7cfc1b89abc4537457ee8f4a83c8e2968daa70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C4=81rlis=20Se=C5=86ko?= Date: Mon, 15 Aug 2022 16:01:46 +0300 Subject: [PATCH 155/240] Make library list in dashboard scrollbable when needed #3019 --- src/widgets/Dashboard.cpp | 30 +++++++++--------------------- src/widgets/Dashboard.ui | 27 +++++++++++++++++++++++++-- 2 files changed, 34 insertions(+), 23 deletions(-) diff --git a/src/widgets/Dashboard.cpp b/src/widgets/Dashboard.cpp index f73b4cc1..1df65b32 100644 --- a/src/widgets/Dashboard.cpp +++ b/src/widgets/Dashboard.cpp @@ -133,33 +133,21 @@ void Dashboard::updateContents() setPlainText(ui->codeSizeLineEdit, QString::number(code) + " bytes"); setPlainText(ui->percentageLineEdit, QString::number(precentage) + "%"); - // dunno: why not label->setText(lines.join("\n")? - while (ui->verticalLayout_2->count() > 0) { - QLayoutItem *item = ui->verticalLayout_2->takeAt(0); - if (item != nullptr) { - QWidget *w = item->widget(); - if (w != nullptr) { - w->deleteLater(); - } - - delete item; - } - } - + ui->libraryList->setPlainText(""); const RzList *libs = bf ? rz_bin_object_get_libs(bf->o) : nullptr; if (libs) { + QString libText; + bool first = true; for (const auto &lib : CutterRzList(libs)) { - auto *label = new QLabel(this); - label->setText(lib); - label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); - label->setTextInteractionFlags(Qt::TextSelectableByMouse); - ui->verticalLayout_2->addWidget(label); + if (!first) { + libText.append("\n"); + } + libText.append(lib); + first = false; } + ui->libraryList->setPlainText(libText); } - QSpacerItem *spacer = new QSpacerItem(1, 1, QSizePolicy::Fixed, QSizePolicy::Expanding); - ui->verticalLayout_2->addSpacerItem(spacer); - // Check if signature info and version info available if (!Core()->getSignatureInfo().size()) { ui->certificateButton->setEnabled(false); diff --git a/src/widgets/Dashboard.ui b/src/widgets/Dashboard.ui index 521da7f2..fe1b7e5a 100644 --- a/src/widgets/Dashboard.ui +++ b/src/widgets/Dashboard.ui @@ -42,7 +42,7 @@ QFrame::Plain - Qt::ScrollBarAlwaysOff + Qt::ScrollBarAsNeeded Qt::ScrollBarAlwaysOff @@ -1331,10 +1331,33 @@ + + + + Qt::Vertical + + + + 20 + 40 + + + + - + + + Qt::ScrollBarAlwaysOff + + + QPlainTextEdit::NoWrap + + + Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse + + From cab85d204ea008e365ba95037e57c0fc424b5ef8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C4=81rlis=20Se=C5=86ko?= Date: Mon, 15 Aug 2022 11:02:08 +0300 Subject: [PATCH 156/240] Set org domain to fix alt tab icon on Linux #3022 --- src/Main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Main.cpp b/src/Main.cpp index 8cb4347f..9c45f5e3 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -74,6 +74,9 @@ int main(int argc, char *argv[]) qRegisterMetaType>(); QCoreApplication::setOrganizationName("rizin"); +#ifndef Q_OS_MACOS // don't set on macOS so that it doesn't affect config path there + QCoreApplication::setOrganizationDomain("rizin.re"); +#endif QCoreApplication::setApplicationName("cutter"); // Importing settings after setting rename, needs separate handling in addition to regular version to version upgrade. From 7a83001a067c7b0190ca586b1089111da59df8b6 Mon Sep 17 00:00:00 2001 From: billow Date: Thu, 18 Aug 2022 06:52:50 +0800 Subject: [PATCH 157/240] convert `?E` to API (#3025) --- src/plugins/sample-cpp/CMakeLists.txt | 3 ++- src/plugins/sample-cpp/CutterSamplePlugin.cpp | 19 ++++++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/src/plugins/sample-cpp/CMakeLists.txt b/src/plugins/sample-cpp/CMakeLists.txt index 93e140f5..53e264c2 100644 --- a/src/plugins/sample-cpp/CMakeLists.txt +++ b/src/plugins/sample-cpp/CMakeLists.txt @@ -2,6 +2,7 @@ cmake_minimum_required(VERSION 3.12) project(cutter-sample-plugin) find_package(Cutter REQUIRED) +find_package(Rizin REQUIRED) set(CUTTER_INSTALL_PLUGDIR "${Cutter_USER_PLUGINDIR}" CACHE STRING "Directory to install Cutter plugin into") set(CMAKE_AUTOMOC ON) @@ -9,5 +10,5 @@ set(CMAKE_AUTOMOC ON) add_library(sample_plugin MODULE CutterSamplePlugin.h CutterSamplePlugin.cpp) -target_link_libraries(sample_plugin PRIVATE Cutter::Cutter) +target_link_libraries(sample_plugin PRIVATE Cutter::Cutter Rizin::Core) install(TARGETS sample_plugin DESTINATION "${CUTTER_INSTALL_PLUGDIR}") diff --git a/src/plugins/sample-cpp/CutterSamplePlugin.cpp b/src/plugins/sample-cpp/CutterSamplePlugin.cpp index bb2264b3..dae6443a 100644 --- a/src/plugins/sample-cpp/CutterSamplePlugin.cpp +++ b/src/plugins/sample-cpp/CutterSamplePlugin.cpp @@ -8,6 +8,7 @@ #include #include #include +#include void CutterSamplePlugin::setupPlugin() {} @@ -46,25 +47,21 @@ CutterSamplePluginWidget::CutterSamplePluginWidget(MainWindow *main) : CutterDoc void CutterSamplePluginWidget::on_seekChanged(RVA addr) { Q_UNUSED(addr); - QString res; - { - TempConfig tempConfig; - tempConfig.set("scr.color", 0); - res = Core()->cmd("?E `pi 1`"); - } + RzCoreLocked core(Core()); + TempConfig tempConfig; + tempConfig.set("scr.color", 0); + QString disasm = Core()->disassembleSingleInstruction(Core()->getOffset()); + QString res = fromOwnedCharPtr(rz_core_clippy(core, disasm.toUtf8().constData())); text->setText(res); } void CutterSamplePluginWidget::on_buttonClicked() { RzCoreLocked core(Core()); - char *fortune = rz_core_fortune_get_random(core); + auto fortune = fromOwned(rz_core_fortune_get_random(core)); if (!fortune) { return; } - // cmdRaw can be used to execute single raw commands - // this is especially good for user-controlled input - QString res = Core()->cmdRaw("?E " + QString::fromUtf8(fortune)); + QString res = fromOwnedCharPtr(rz_core_clippy(core, fortune.get())); text->setText(res); - rz_mem_free(fortune); } From e6db27135dcb9f2aa46bde91ac5c82e64ed51df3 Mon Sep 17 00:00:00 2001 From: Edd Barrett Date: Thu, 18 Aug 2022 15:18:40 +0000 Subject: [PATCH 158/240] Fix build on 32-bit systems. (#3032) --- src/widgets/GraphGridLayout.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/GraphGridLayout.cpp b/src/widgets/GraphGridLayout.cpp index cf100e24..0cf7840d 100644 --- a/src/widgets/GraphGridLayout.cpp +++ b/src/widgets/GraphGridLayout.cpp @@ -554,7 +554,7 @@ void GraphGridLayout::calculateEdgeMainColumn(GraphGridLayout::LayoutState &stat struct Event { - size_t blockId; + ut64 blockId; size_t edgeId; int row; enum Type { Edge = 0, Block = 1 } type; From d6370541e7e0f2ca3851b6e839925373c842e25c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Wed, 24 Aug 2022 15:51:00 +0200 Subject: [PATCH 159/240] Generate and deploy source tarball (Fix #2878) (#3036) This builds a real tarball, as opposed to the flawed GitHub-generated one, and also includes the following changes: Individual builds now have dedicated names like "linux-x86_64". The structure in the yml is now very similar to how it is in rizin. Since that means builds are renamed, the filename has also been changed from the meaningless "ccpp.yml" to "ci.yml", as that would have happened sooner or later anyway and now will not produce additional intermediate rename states. The workflow name inside that file is now also just "CI" since adding "Cutter" there is redundant. --- .github/workflows/{ccpp.yml => ci.yml} | 56 +++++++++++++++++++++----- scripts/tarball.sh | 32 +++++++++++++++ 2 files changed, 77 insertions(+), 11 deletions(-) rename .github/workflows/{ccpp.yml => ci.yml} (85%) create mode 100755 scripts/tarball.sh diff --git a/.github/workflows/ccpp.yml b/.github/workflows/ci.yml similarity index 85% rename from .github/workflows/ccpp.yml rename to .github/workflows/ci.yml index ff9bde5f..edd72529 100644 --- a/.github/workflows/ccpp.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -name: Cutter CI +name: CI on: push: @@ -16,25 +16,48 @@ on: jobs: build: + name: ${{ matrix.name }} runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-20.04, ubuntu-18.04, macos-latest, windows-2019] - python-version: [3.7.x] - system-deps: [false] - cc-override: [default] - cxx-override: [default] + name: [ + linux-x86_64, + linux-x86_64-system-deps, + macos-x86_64, + windows-x86_64, + tarball + ] include: - - os: windows-2019 + - name: windows-x86_64 + os: windows-2019 package: true - - os: ubuntu-18.04 # ensure that Cutter can be built at least in basic config on Ubuntu 18.04 using sytem libraries + system-deps: false + python-version: 3.7.x + - name: linux-x86_64-system-deps # ensure that Cutter can be built at least in basic config on Ubuntu 18.04 using sytem libraries + os: ubuntu-18.04 python-version: 3.6.x system-deps: true cc-override: '/usr/bin/gcc-7' cxx-override: '/usr/bin/g++-7' - - os: ubuntu-18.04 # release package build + - name: linux-x86_64 + os: ubuntu-18.04 + python-version: 3.7.x system-deps: false package: true + cc-override: default + cxx-override: default + - name: macos-x86_64 + os: macos-latest + python-version: 3.7.x + system-deps: false + package: true + cc-override: default + cxx-override: default + - name: tarball + python-version: 3.7.x + os: ubuntu-20.04 + system-deps: false + tarball: true # Prevent one job from pausing the rest fail-fast: false steps: @@ -159,6 +182,7 @@ jobs: export APPIMAGE_FILE="Cutter-${PACKAGE_ID}-Linux-x86_64.AppImage" mv Cutter-*-x86_64.AppImage "$APPIMAGE_FILE" echo PACKAGE_NAME=$APPIMAGE_FILE >> $GITHUB_ENV + echo PACKAGE_PATH=build/$APPIMAGE_FILE >> $GITHUB_ENV echo UPLOAD_ASSET_TYPE=application/x-executable >> $GITHUB_ENV fi - name: cmake macos @@ -199,6 +223,7 @@ jobs: make package export CUTTER_VERSION=$(python3 ../scripts/get_version.py) echo PACKAGE_NAME=${PACKAGE_NAME}.dmg >> $GITHUB_ENV + echo PACKAGE_PATH=build/${PACKAGE_NAME}.dmg >> $GITHUB_ENV echo UPLOAD_ASSET_TYPE=application/x-apple-diskimage >> $GITHUB_ENV - name: windows dependencies if: contains(matrix.os, 'windows') @@ -241,12 +266,21 @@ jobs: cmake --build . --config Release cmake --build . --config Release --target package echo PACKAGE_NAME=%PACKAGE_NAME%.zip >> %GITHUB_ENV% + echo PACKAGE_PATH=build/%PACKAGE_NAME%.zip >> %GITHUB_ENV% echo UPLOAD_ASSET_TYPE=application/zip >> %GITHUB_ENV% + - name: Create tarball + if: matrix.tarball + shell: bash + run: | + scripts/tarball.sh "Cutter-${PACKAGE_ID}" + echo PACKAGE_NAME=Cutter-${PACKAGE_ID}-src.tar.gz >> $GITHUB_ENV + echo PACKAGE_PATH=Cutter-${PACKAGE_ID}-src.tar.gz >> $GITHUB_ENV + echo UPLOAD_ASSET_TYPE=application/gzip >> $GITHUB_ENV - uses: actions/upload-artifact@v2 if: env.PACKAGE_NAME != null with: name: ${{ env.PACKAGE_NAME }} - path: build/${{ env.PACKAGE_NAME }} + path: ${{ env.PACKAGE_PATH }} - name: Get release if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') id: get_release @@ -260,6 +294,6 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: upload_url: ${{ steps.get_release.outputs.upload_url }} - asset_path: build/${{ env.PACKAGE_NAME }} + asset_path: ${{ env.PACKAGE_PATH }} asset_name: ${{ env.PACKAGE_NAME }} asset_content_type: ${{ env.UPLOAD_ASSET_TYPE }} diff --git a/scripts/tarball.sh b/scripts/tarball.sh new file mode 100755 index 00000000..3876b449 --- /dev/null +++ b/scripts/tarball.sh @@ -0,0 +1,32 @@ +#!/bin/bash + +NAME=${1:-Cutter} + +set -xe +cd $(dirname "${BASH_SOURCE[0]}")/.. + +shopt -s extglob +shopt -s dotglob +mkdir "${NAME}" +cp -r !(${NAME}) "${NAME}" + +pushd "${NAME}" +git clean -dxff . +git submodule update --init --recursive + +pushd rizin +git clean -dxff . +# Possible option: pre-download all subproject, however this makes the tarball huge. +# As opposed to meson dist used for rizin tarballs, this will not just download the ones +# used in a default build, but all of them, including multiple capstone variants. +# meson subprojects download +popd + +pushd src/translations +git clean -dxff . +popd + +find . -name ".git*" | xargs rm -rfv +popd + +tar -czvf "${NAME}-src.tar.gz" "${NAME}" From a2ed7971aad8946b4cdf93a540c27255e8f5b654 Mon Sep 17 00:00:00 2001 From: turlututututu Date: Fri, 2 Sep 2022 23:51:30 +0200 Subject: [PATCH 160/240] Update iterator synthax to be compatible with cpp17 (#3033) std::iterator is deprecated in cpp17 thus in order to be able to upgrade to cpp17 if needed we manually define the relevant types for iterator. See https://www.fluentcpp.com/2018/05/08/std-iterator-deprecated/ for more details. --- src/core/RizinCpp.h | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/src/core/RizinCpp.h b/src/core/RizinCpp.h index ae4fcb03..e39f964b 100644 --- a/src/core/RizinCpp.h +++ b/src/core/RizinCpp.h @@ -71,8 +71,15 @@ private: const RzPVector *const vec; public: - class iterator : public std::iterator + class iterator { + public: + using iterator_category = std::input_iterator_tag; + using value_type = T *; + using difference_type = ptrdiff_t; + using pointer = T **; + using reference = T *&; + private: T **p; @@ -107,8 +114,15 @@ private: const RzList *const list; public: - class iterator : public std::iterator + class iterator { + public: + using iterator_category = std::input_iterator_tag; + using value_type = T *; + using difference_type = ptrdiff_t; + using pointer = T **; + using reference = T *&; + private: RzListIter *iter; From 2e414069c5a5b6eae78c5ca5e3742ce55001f37a Mon Sep 17 00:00:00 2001 From: karliss Date: Tue, 6 Sep 2022 18:46:39 +0300 Subject: [PATCH 161/240] Support editing in hex editor (#3026) --- src/widgets/HexWidget.cpp | 1004 ++++++++++++++++++++++++++++++++++--- src/widgets/HexWidget.h | 178 +++++-- 2 files changed, 1084 insertions(+), 98 deletions(-) diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index 39f63186..d933b944 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -26,6 +26,7 @@ static constexpr uint64_t MAX_COPY_SIZE = 128 * 1024 * 1024; static constexpr int MAX_LINE_WIDTH_PRESET = 32; static constexpr int MAX_LINE_WIDTH_BYTES = 128 * 1024; +static constexpr int WARNING_TIME_MS = 500; HexWidget::HexWidget(QWidget *parent) : QScrollArea(parent), @@ -42,7 +43,8 @@ HexWidget::HexWidget(QWidget *parent) showHeader(true), showAscii(true), showExHex(true), - showExAddr(true) + showExAddr(true), + warningTimer(this) { setMouseTracking(true); setFocusPolicy(Qt::FocusPolicy::StrongFocus); @@ -103,7 +105,7 @@ HexWidget::HexWidget(QWidget *parent) actionItemBigEndian = new QAction(tr("Big Endian"), this); actionItemBigEndian->setCheckable(true); actionItemBigEndian->setEnabled(false); - connect(actionItemBigEndian, &QAction::triggered, this, &HexWidget::setItemEndianess); + connect(actionItemBigEndian, &QAction::triggered, this, &HexWidget::setItemEndianness); actionHexPairs = new QAction(tr("Bytes as pairs"), this); actionHexPairs->setCheckable(true); @@ -125,14 +127,14 @@ HexWidget::HexWidget(QWidget *parent) actionComment = new QAction(tr("Add Comment"), this); actionComment->setShortcutContext(Qt::ShortcutContext::WidgetWithChildrenShortcut); actionComment->setShortcut(Qt::Key_Semicolon); - connect(actionComment, &QAction::triggered, this, &HexWidget::on_actionAddComment_triggered); + connect(actionComment, &QAction::triggered, this, &HexWidget::onActionAddCommentTriggered); addAction(actionComment); // delete comment option actionDeleteComment = new QAction(tr("Delete Comment"), this); actionDeleteComment->setShortcutContext(Qt::ShortcutContext::WidgetWithChildrenShortcut); connect(actionDeleteComment, &QAction::triggered, this, - &HexWidget::on_actionDeleteComment_triggered); + &HexWidget::onActionDeleteCommentTriggered); addAction(actionDeleteComment); actionSelectRange = new QAction(tr("Select range"), this); @@ -183,8 +185,13 @@ HexWidget::HexWidget(QWidget *parent) connect(actionIncDec, &QAction::triggered, this, &HexWidget::w_increaseDecrease); actionsWriteOther.append(actionIncDec); + actionKeyboardEdit = new QAction(tr("Edit with keyboard"), this); + actionKeyboardEdit->setCheckable(true); + connect(actionKeyboardEdit, &QAction::triggered, this, &HexWidget::onKeyboardEditTriggered); + connect(actionKeyboardEdit, &QAction::toggled, this, &HexWidget::onKeyboardEditChanged); + connect(this, &HexWidget::selectionChanged, this, - [this](Selection selection) { actionCopy->setEnabled(!selection.empty); }); + [this](Selection newSelection) { actionCopy->setEnabled(!newSelection.empty); }); updateMetrics(); updateItemLength(); @@ -202,9 +209,10 @@ HexWidget::HexWidget(QWidget *parent) cursor.startBlinking(); updateColors(); -} -HexWidget::~HexWidget() {} + warningTimer.setSingleShot(true); + connect(&warningTimer, &QTimer::timeout, this, &HexWidget::hideWarningRect); +} void HexWidget::setMonospaceFont(const QFont &font) { @@ -228,6 +236,8 @@ void HexWidget::setItemSize(int nbytes) if (!values.contains(nbytes)) return; + finishEditingWord(); + itemByteLen = nbytes; if (itemByteLen > rowSizeBytes) { rowSizeBytes = itemByteLen; @@ -236,7 +246,12 @@ void HexWidget::setItemSize(int nbytes) actionsItemFormat.at(ItemFormatFloat)->setEnabled(nbytes >= 4); actionItemBigEndian->setEnabled(nbytes != 1); + refreshWordEditState(); + updateItemLength(); + if (!cursorOnAscii && cursor.address % itemByteLen) { + moveCursor(-int(cursor.address % itemByteLen)); + } fetchData(); updateCursorMeta(); @@ -245,6 +260,8 @@ void HexWidget::setItemSize(int nbytes) void HexWidget::setItemFormat(ItemFormat format) { + finishEditingWord(); + itemFormat = format; bool sizeEnabled = true; @@ -253,6 +270,8 @@ void HexWidget::setItemFormat(ItemFormat format) actionsItemSize.at(0)->setEnabled(sizeEnabled); actionsItemSize.at(1)->setEnabled(sizeEnabled); + refreshWordEditState(); + updateItemLength(); fetchData(); updateCursorMeta(); @@ -382,7 +401,7 @@ void HexWidget::selectRange(RVA start, RVA end) void HexWidget::clearSelection() { - setCursorAddr(cursor.address, false); + setCursorAddr(BasicCursor(cursor.address), false); emit selectionChanged(getSelection()); } @@ -393,7 +412,16 @@ HexWidget::Selection HexWidget::getSelection() void HexWidget::seek(uint64_t address) { - setCursorAddr(address); + if (!cursorOnAscii) { + // when other widget causes seek to the middle of word + // switch to ascii column which operates with byte positions + auto viewOffset = startAddress % itemByteLen; + auto addrOffset = address % itemByteLen; + if ((addrOffset + itemByteLen - viewOffset) % itemByteLen) { + setCursorOnAscii(true); + } + } + setCursorAddr(BasicCursor(address)); } void HexWidget::refresh() @@ -402,8 +430,9 @@ void HexWidget::refresh() viewport()->update(); } -void HexWidget::setItemEndianess(bool bigEndian) +void HexWidget::setItemEndianness(bool bigEndian) { + finishEditingWord(); itemBigEndian = bigEndian; updateCursorMeta(); // Update cached item character @@ -422,6 +451,7 @@ void HexWidget::updateColors() defColor = Config()->getColor("btext"); addrColor = Config()->getColor("func_var_addr"); diffColor = Config()->getColor("graph.diff.unmatch"); + warningColor = QColor("red"); updateCursorMeta(); viewport()->update(); @@ -450,6 +480,11 @@ void HexWidget::paintEvent(QPaintEvent *event) drawItemArea(painter); drawAsciiArea(painter); + if (warningRectVisible) { + painter.setPen(warningColor); + painter.drawRect(warningRect); + } + if (!cursorEnabled) return; @@ -467,6 +502,11 @@ void HexWidget::updateWidth() horizontalScrollBar()->setSingleStep(charWidth); } +bool HexWidget::isFixedWidth() const +{ + return itemFormat == ItemFormatHex || itemFormat == ItemFormatOct; +} + void HexWidget::resizeEvent(QResizeEvent *event) { int oldByteCount = bytesPerScreen(); @@ -526,22 +566,98 @@ void HexWidget::mousePressEvent(QMouseEvent *event) if (event->button() == Qt::LeftButton) { bool selectingData = itemArea.contains(pos); bool selecting = selectingData || asciiArea.contains(pos); + bool holdingShift = event->modifiers() == Qt::ShiftModifier; + + // move cursor within actively edited item + if (selectingData && !holdingShift && editWordState >= EditWordState::WriteNotEdited) { + + auto editWordArea = itemRectangle(cursor.address - startAddress); + if (editWordArea.contains(pos)) { + int wordOffset = 0; + auto cursorPosition = screenPosToAddr(pos, false, &wordOffset); + if (cursorPosition.address == cursor.address + // allow selecting after last character only when cursor limited to current word + && (wordOffset < editWord.length() + || navigationMode == HexNavigationMode::WordChar)) { + editWordPos = std::max(0, wordOffset); + editWordPos = std::min(editWordPos, editWord.length()); + + if (isFixedWidth()) { + updatingSelection = true; + auto selectionCursor = cursorPosition; + if (editWordPos > itemCharLen / 2) { + selectionCursor += itemByteLen; + } + selection.init(selectionCursor); + } + + viewport()->update(); + return; + } + } + } + + // cursor within any item if the mode allows + if (selectingData && !holdingShift && editWordState >= EditWordState::WriteNotStarted + && navigationMode == HexNavigationMode::AnyChar) { + updatingSelection = true; + setCursorOnAscii(false); + int wordOffset = 0; + auto cursorPosition = screenPosToAddr(pos, false, &wordOffset); + finishEditingWord(); + if (isFixedWidth() && wordOffset >= itemCharLen - itemPrefixLen) { + wordOffset = 0; + cursorPosition += itemByteLen; + } + setCursorAddr(cursorPosition, holdingShift); + auto selectionPosition = currentAreaPosToAddr(pos, true); + selection.init(selectionPosition); + emit selectionChanged(getSelection()); + + if (wordOffset > 0) { + startEditWord(); + editWordPos = std::min(wordOffset, editWord.length() - 1); + } + viewport()->update(); + return; + } + if (selecting) { + finishEditingWord(); + updatingSelection = true; setCursorOnAscii(!selectingData); auto cursorPosition = currentAreaPosToAddr(pos, true); - setCursorAddr(cursorPosition, event->modifiers() == Qt::ShiftModifier); + setCursorAddr(cursorPosition, holdingShift); viewport()->update(); } } } +void HexWidget::mouseDoubleClickEvent(QMouseEvent *event) +{ + QPoint pos(event->pos()); + pos.rx() += horizontalScrollBar()->value(); + + if (event->button() == Qt::LeftButton && !isFixedWidth() + && editWordState == EditWordState::WriteNotStarted && itemArea.contains(pos)) { + int wordOffset = 0; + auto cursorPosition = screenPosToAddr(pos, false, &wordOffset); + setCursorAddr(cursorPosition, false); + startEditWord(); + int padding = std::max(0, itemCharLen - editWord.length()); + editWordPos = std::max(0, wordOffset - padding); + editWordPos = std::min(editWordPos, editWord.length()); + } +} + void HexWidget::mouseReleaseEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) { if (selection.isEmpty()) { - selection.init(cursor.address); + selection.init(BasicCursor(cursor.address)); cursorEnabled = true; + viewport()->update(); } updatingSelection = false; } @@ -560,13 +676,14 @@ void HexWidget::wheelEvent(QWheelEvent *event) startAddress = 0; } else if (delta > 0 && data->maxIndex() < static_cast(bytesPerScreen())) { startAddress = 0; + } else if ((data->maxIndex() - startAddress) + <= static_cast(bytesPerScreen() + delta - 1)) { + startAddress = (data->maxIndex() - bytesPerScreen()) + 1; } else { startAddress += delta; } + fetchData(); - if ((data->maxIndex() - startAddress) <= static_cast(bytesPerScreen() + delta - 1)) { - startAddress = (data->maxIndex() - bytesPerScreen()) + 1; - } if (cursor.address >= startAddress && cursor.address <= lastVisibleAddr()) { /* Don't enable cursor blinking if selection isn't empty */ cursorEnabled = selection.isEmpty(); @@ -577,6 +694,304 @@ void HexWidget::wheelEvent(QWheelEvent *event) viewport()->update(); } +bool HexWidget::validCharForEdit(QChar digit) +{ + switch (itemFormat) { + case ItemFormatHex: + return (digit >= '0' && digit <= '9') || (digit >= 'a' && digit <= 'f') + || (digit >= 'A' && digit <= 'F'); + case ItemFormatOct: { + if (editWordPos > 0) { + return (digit >= '0' && digit <= '7'); + } else { + int bitsInMSD = (itemByteLen * 8) % 3; + int biggestDigit = (1 << bitsInMSD) - 1; + return digit >= '0' && digit <= char('0' + biggestDigit); + } + } + case ItemFormatDec: + return (digit >= '0' && digit <= '9'); + case ItemFormatSignedDec: + return (digit >= '0' && digit <= '9') || digit == '-'; + case ItemFormatFloat: + return (digit >= '0' && digit <= '9') || digit == '-' || digit == '+' || digit == '.' + || digit == ',' || digit == '+' || digit == 'e' || digit == 'E' || digit == 'i' + || digit == 'n' || digit == 'f' || digit == 'I' || digit == 'N' || digit == 'F' + || digit == 'a' || digit == 'A'; + } + + return false; +} + +void HexWidget::movePrevEditCharAny() +{ + if (!selection.isEmpty()) { + clearSelection(); + } + editWordPos -= 1; + if (editWordPos < 0) { + finishEditingWord(); + if (moveCursor(-itemByteLen, false, OverflowMove::Ignore)) { + startEditWord(); + editWordPos = editWord.length() - 1; + } + } + viewport()->update(); +} + +void HexWidget::typeOverwriteModeChar(QChar c) +{ + if (editWordState < EditWordState::WriteNotEdited || !isFixedWidth()) { + return; + } + editWord[editWordPos] = c; + editWordPos++; + editWordState = EditWordState::WriteEdited; + if (editWordPos >= editWord.length()) { + finishEditingWord(); + bool moved = moveCursor(itemByteLen, false, OverflowMove::Ignore); + startEditWord(); + if (!moved) { + editWordPos = editWord.length() - 1; + } + } +} + +HexWidget::HexNavigationMode HexWidget::defaultNavigationMode() +{ + switch (editWordState) { + case EditWordState::Read: + return HexNavigationMode::Words; + case EditWordState::WriteNotStarted: + return isFixedWidth() ? HexNavigationMode::AnyChar : HexNavigationMode::Words; + case EditWordState::WriteNotEdited: + case EditWordState::WriteEdited: + return isFixedWidth() ? HexNavigationMode::AnyChar : HexNavigationMode::WordChar; + } + return HexNavigationMode::Words; +} + +void HexWidget::refreshWordEditState() +{ + navigationMode = defaultNavigationMode(); +} + +bool HexWidget::handleAsciiWrite(QKeyEvent *event) +{ + if (!cursorOnAscii || !canKeyboardEdit()) { + return false; + } + if (event->key() == Qt::Key_Backspace || event->matches(QKeySequence::Backspace)) { + if (!selection.isEmpty()) { + writeZeros(selection.start(), selection.size()); + } else { + moveCursor(-1, false); + writeZeros(cursor.address, 1); + } + return true; + } + if (event->key() == Qt::Key_Delete || event->matches(QKeySequence::Delete)) { + if (!selection.isEmpty()) { + writeZeros(selection.start(), selection.size()); + } else { + writeZeros(cursor.address, 1); + moveCursor(1, false); + } + return true; + } + QString text; + if (event->matches(QKeySequence::Paste)) { + text = QApplication::clipboard()->text(); + if (text.length() <= 0) { + return false; + } + } else { + text = event->text(); + if (text.length() <= 0) { + return false; + } + QChar c = text[0]; + if (c <= '\x1f' || c == '\x7f') { + return false; + } + } + + auto bytes = text.toUtf8(); // TODO:#3028 use selected text encoding + auto address = getLocationAddress(); + clearSelection(); + data->write(reinterpret_cast(bytes.data()), address, bytes.length()); + seek(address + bytes.length()); + viewport()->update(); + return true; +} + +bool HexWidget::handleNumberWrite(QKeyEvent *event) +{ + if (editWordState < EditWordState::WriteNotStarted) { + return false; + } + bool overwrite = isFixedWidth(); + auto keyText = event->text(); + bool editingWord = editWordState >= EditWordState::WriteNotEdited; + if (keyText.length() > 0 && validCharForEdit(keyText[0])) { + if (!selection.isEmpty()) { + setCursorAddr(BasicCursor(selection.start())); + } + if (!editingWord) { + startEditWord(); + } + if (overwrite) { + typeOverwriteModeChar(keyText[0]); + } else if (!editingWord /* && !overwrite */) { + editWord = keyText; + editWordPos = editWord.length(); + editWordState = EditWordState::WriteEdited; + } else if (itemFormat == ItemFormatFloat || editWord.length() < itemCharLen) { + editWord.insert(editWordPos, keyText); + editWordPos += keyText.length(); + editWordState = EditWordState::WriteEdited; + } + maybeFlushCharEdit(); + return true; + } + if (event->matches(QKeySequence::Paste) && (editingWord || overwrite)) { + QString text = QApplication::clipboard()->text(); + if (text.length() > 0) { + if (overwrite) { + startEditWord(); + for (QChar c : text) { + if (validCharForEdit(c)) { + typeOverwriteModeChar(c); + } + } + } else { + editWord.insert(editWordPos, text); + editWordPos += text.length(); + editWordState = EditWordState::WriteEdited; + } + } + maybeFlushCharEdit(); + return true; + } + if (editingWord) { + if (event->matches(QKeySequence::Cancel)) { + cancelEditedWord(); + return true; + } else if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) { + bool needToAdvance = + !(editWordPos == 0 && overwrite && editWordState < EditWordState::WriteEdited); + if (finishEditingWord(false) && needToAdvance) { + moveCursor(itemByteLen); + } + return true; + } + } + if (event->matches(QKeySequence::Delete)) { + if (!selection.isEmpty()) { + writeZeros(selection.start(), selection.size()); + clearSelection(); + } else { + startEditWord(); + if (overwrite) { + typeOverwriteModeChar('0'); + } else if (editWordPos < editWord.length()) { + editWord.remove(editWordPos, 1); + editWordState = EditWordState::WriteEdited; + } + } + maybeFlushCharEdit(); + return true; + } + if (event->matches(QKeySequence::DeleteEndOfWord) && selection.isEmpty()) { + startEditWord(); + if (overwrite) { + for (int i = editWordPos; i < editWord.length(); i++) { + typeOverwriteModeChar('0'); + } + } else if (editWordPos < editWord.length()) { + editWord.remove(editWordPos, editWord.length()); + editWordState = EditWordState::WriteEdited; + } + maybeFlushCharEdit(); + return true; + } + if (event->matches(QKeySequence::DeleteStartOfWord) && selection.isEmpty()) { + if (!editingWord || (overwrite && editWordPos == 0)) { + if (!moveCursor(-itemByteLen, false, OverflowMove::Ignore)) { + return false; + } + startEditWord(); + editWordPos = editWord.length(); + } + if (overwrite) { + while (editWordPos > 0) { + editWordPos--; + editWord[editWordPos] = '0'; + } + editWordState = EditWordState::WriteEdited; + maybeFlushCharEdit(); + return true; + } else { + if (editWordPos > 0) { + editWord.remove(0, editWordPos); + editWordState = EditWordState::WriteEdited; + editWordPos = 0; + maybeFlushCharEdit(); + return true; + } + } + return false; + } + + if (event->key() == Qt::Key_Backspace) { + if (!selection.isEmpty()) { + writeZeros(selection.start(), selection.size()); + clearSelection(); + setCursorAddr(BasicCursor(selection.start()), false); + return true; + } else { + if (!editingWord || (overwrite && editWordPos == 0)) { + if (!moveCursor(-itemByteLen, false, OverflowMove::Ignore)) { + return false; + } + startEditWord(); + editWordPos = editWord.length(); + } + if (editWordPos > 0) { + editWordPos -= 1; + if (overwrite) { + editWord[editWordPos] = '0'; + } else { + editWord.remove(editWordPos, 1); + } + editWordState = EditWordState::WriteEdited; + maybeFlushCharEdit(); + return true; + } + } + return false; + } + + return false; +} + +bool HexWidget::event(QEvent *event) +{ + // prefer treating keys like 's' 'g' '.' as typing input instead of global shortcuts + if (event->type() == QEvent::ShortcutOverride) { + auto keyEvent = static_cast(event); + auto modifiers = keyEvent->modifiers(); + if ((modifiers == Qt::NoModifier || modifiers == Qt::ShiftModifier + || modifiers == Qt::KeypadModifier) + && keyEvent->key() < Qt::Key_Escape && canKeyboardEdit()) { + keyEvent->accept(); + return true; + } + } + + return QScrollArea::event(event); +} + void HexWidget::keyPressEvent(QKeyEvent *event) { bool select = false; @@ -591,26 +1006,126 @@ void HexWidget::keyPressEvent(QKeyEvent *event) } return false; }; - if (moveOrSelect(QKeySequence::MoveToNextLine, QKeySequence::SelectNextLine)) { - moveCursor(itemRowByteLen(), select); - } else if (moveOrSelect(QKeySequence::MoveToPreviousLine, QKeySequence::SelectPreviousLine)) { - moveCursor(-itemRowByteLen(), select); - } else if (moveOrSelect(QKeySequence::MoveToNextChar, QKeySequence::SelectNextChar)) { - moveCursor(cursorOnAscii ? 1 : itemByteLen, select); - } else if (moveOrSelect(QKeySequence::MoveToPreviousChar, QKeySequence::SelectPreviousChar)) { - moveCursor(cursorOnAscii ? -1 : -itemByteLen, select); - } else if (moveOrSelect(QKeySequence::MoveToNextPage, QKeySequence::SelectNextPage)) { - moveCursor(bytesPerScreen(), select); - } else if (moveOrSelect(QKeySequence::MoveToPreviousPage, QKeySequence::SelectPreviousPage)) { - moveCursor(-bytesPerScreen(), select); - } else if (moveOrSelect(QKeySequence::MoveToStartOfLine, QKeySequence::SelectStartOfLine)) { - int linePos = int((cursor.address % itemRowByteLen()) - (startAddress % itemRowByteLen())); - moveCursor(-linePos, select); - } else if (moveOrSelect(QKeySequence::MoveToEndOfLine, QKeySequence::SelectEndOfLine)) { - int linePos = int((cursor.address % itemRowByteLen()) - (startAddress % itemRowByteLen())); - moveCursor(itemRowByteLen() - linePos, select); + + if (canKeyboardEdit()) { + if (handleAsciiWrite(event)) { + viewport()->update(); + return; + } + if (editWordState >= EditWordState::WriteNotStarted && !cursorOnAscii) { + if (handleNumberWrite(event)) { + viewport()->update(); + return; + } + } + } + + if (cursorOnAscii || navigationMode == HexNavigationMode::Words + || navigationMode == HexNavigationMode::AnyChar) { + if (moveOrSelect(QKeySequence::MoveToNextPage, QKeySequence::SelectNextPage)) { + moveCursor(bytesPerScreen(), select); + } else if (moveOrSelect(QKeySequence::MoveToPreviousPage, + QKeySequence::SelectPreviousPage)) { + moveCursor(-bytesPerScreen(), select); + } else if (moveOrSelect(QKeySequence::MoveToStartOfLine, QKeySequence::SelectStartOfLine)) { + int linePos = + int((cursor.address % itemRowByteLen()) - (startAddress % itemRowByteLen())); + moveCursor(-linePos, select); + } else if (moveOrSelect(QKeySequence::MoveToEndOfLine, QKeySequence::SelectEndOfLine)) { + int linePos = + int((cursor.address % itemRowByteLen()) - (startAddress % itemRowByteLen())); + moveCursor(itemRowByteLen() - linePos, select); + } + } + + if (navigationMode == HexNavigationMode::Words || cursorOnAscii) { + if (moveOrSelect(QKeySequence::MoveToNextLine, QKeySequence::SelectNextLine)) { + moveCursor(itemRowByteLen(), select, OverflowMove::Ignore); + } else if (moveOrSelect(QKeySequence::MoveToPreviousLine, + QKeySequence::SelectPreviousLine)) { + moveCursor(-itemRowByteLen(), select, OverflowMove::Ignore); + } else if (moveOrSelect(QKeySequence::MoveToNextChar, QKeySequence::SelectNextChar) + || moveOrSelect(QKeySequence::MoveToNextWord, QKeySequence::SelectNextWord)) { + moveCursor(cursorOnAscii ? 1 : itemByteLen, select); + } else if (moveOrSelect(QKeySequence::MoveToPreviousChar, QKeySequence::SelectPreviousChar) + || moveOrSelect(QKeySequence::MoveToPreviousWord, + QKeySequence::SelectPreviousWord)) { + moveCursor(cursorOnAscii ? -1 : -itemByteLen, select); + } + } else if (navigationMode == HexNavigationMode::AnyChar && !cursorOnAscii) { + if (moveOrSelect(QKeySequence::MoveToNextLine, QKeySequence::SelectNextLine)) { + moveCursorKeepEditOffset(itemRowByteLen(), select, OverflowMove::Ignore); + } else if (moveOrSelect(QKeySequence::MoveToPreviousLine, + QKeySequence::SelectPreviousLine)) { + moveCursorKeepEditOffset(-itemRowByteLen(), select, OverflowMove::Ignore); + } else if (moveOrSelect(QKeySequence::MoveToNextChar, QKeySequence::SelectNextChar)) { + if (select) { + moveCursor(itemByteLen, select); + } else { + if (!selection.isEmpty()) { + clearSelection(); + } + if (editWordState == EditWordState::WriteNotStarted) { + startEditWord(); + } + editWordPos += 1; + if (editWordPos >= editWord.length()) { + bool moved = moveCursor(itemByteLen, false, OverflowMove::Ignore); + startEditWord(); + if (!moved) { + editWordPos = editWord.length() - 1; + } + } + } + viewport()->update(); + } else if (event->matches(QKeySequence::MoveToPreviousChar)) { + movePrevEditCharAny(); + } else if (event->matches(QKeySequence::SelectPreviousChar)) { + moveCursor(-itemByteLen, true); + } else if (moveOrSelect(QKeySequence::MoveToNextWord, QKeySequence::SelectNextWord)) { + moveCursor(itemByteLen, select); + } else if (event->matches(QKeySequence::MoveToPreviousWord)) { + if (editWordPos > 0) { + editWordPos = 0; + viewport()->update(); + } else { + moveCursor(-itemByteLen, false); + } + } else if (event->matches(QKeySequence::SelectPreviousWord)) { + moveCursor(-itemByteLen, true); + } + } else if (navigationMode == HexNavigationMode::WordChar) { + if (event->matches(QKeySequence::MoveToNextChar)) { + editWordPos = std::min(editWord.length(), editWordPos + 1); + viewport()->update(); + } else if (event->matches(QKeySequence::MoveToPreviousChar)) { + editWordPos = std::max(0, editWordPos - 1); + viewport()->update(); + } else if (event->matches(QKeySequence::MoveToStartOfLine)) { + editWordPos = 0; + viewport()->update(); + } else if (event->matches(QKeySequence::MoveToEndOfLine)) { + editWordPos = editWord.length(); + viewport()->update(); + } else if (event->matches(QKeySequence::MoveToPreviousWord)) { + if (editWordPos > 0) { + editWordPos = 0; + } else { + moveCursor(-itemByteLen, select); + startEditWord(); + } + viewport()->update(); + } else if (event->matches(QKeySequence::MoveToNextWord)) { + if (editWordPos < editWord.length()) { + editWordPos = editWord.length(); + } else { + moveCursor(itemByteLen, select); + startEditWord(); + editWordPos = editWord.length(); + } + viewport()->update(); + } } - // viewport()->update(); } void HexWidget::contextMenuEvent(QContextMenuEvent *event) @@ -645,7 +1160,11 @@ void HexWidget::contextMenuEvent(QContextMenuEvent *event) actionComment->setText(tr("Edit Comment")); } - QMenu *menu = new QMenu(); + if (!ioModesController.canWrite()) { + actionKeyboardEdit->setChecked(false); + } + + auto *menu = new QMenu(this); QMenu *sizeMenu = menu->addMenu(tr("Item size:")); sizeMenu->addActions(actionsItemSize); QMenu *formatMenu = menu->addMenu(tr("Item format:")); @@ -657,6 +1176,8 @@ void HexWidget::contextMenuEvent(QContextMenuEvent *event) writeMenu->addActions(actionsWriteString); writeMenu->addSeparator(); writeMenu->addActions(actionsWriteOther); + menu->addAction(actionKeyboardEdit); + menu->addSeparator(); menu->addAction(actionCopy); disableOutsideSelectionActions(mouseOutsideSelection); @@ -700,23 +1221,20 @@ void HexWidget::copy() void HexWidget::copyAddress() { - uint64_t addr = cursor.address; - if (!selection.isEmpty()) { - addr = selection.start(); - } + uint64_t addr = getLocationAddress(); QClipboard *clipboard = QApplication::clipboard(); clipboard->setText(RzAddressString(addr)); } // slot for add comment action -void HexWidget::on_actionAddComment_triggered() +void HexWidget::onActionAddCommentTriggered() { uint64_t addr = cursor.address; CommentsDialog::addOrEditComment(addr, this); } // slot for deleting comment action -void HexWidget::on_actionDeleteComment_triggered() +void HexWidget::onActionDeleteCommentTriggered() { uint64_t addr = cursor.address; Core()->delComment(addr); @@ -731,6 +1249,20 @@ void HexWidget::onRangeDialogAccepted() selectRange(rangeDialog.getStartAddress(), rangeDialog.getEndAddress()); } +void HexWidget::writeZeros(uint64_t address, uint64_t length) +{ + const uint64_t MAX_BUFFER = 1024; + std::vector zeroes(std::min(MAX_BUFFER, length), 0); + while (length > zeroes.size()) { + data->write(zeroes.data(), address, zeroes.size()); + address += zeroes.size(); + length -= zeroes.size(); + } + if (length > 0) { + data->write(zeroes.data(), address, length); + } +} + void HexWidget::w_writeString() { if (!ioModesController.prepareForWriting()) { @@ -825,10 +1357,7 @@ void HexWidget::w_writeZeros() return; } { - RzCoreLocked core(Core()); - auto *buf = (uint8_t *)calloc(len, sizeof(uint8_t)); - rz_core_write_at(core, getLocationAddress(), buf, len); - free(buf); + writeZeros(getLocationAddress(), len); } refresh(); } @@ -964,15 +1493,42 @@ void HexWidget::w_writeCString() refresh(); } +void HexWidget::onKeyboardEditTriggered(bool enabled) +{ + if (!enabled) { + return; + } + if (!ioModesController.prepareForWriting()) { + actionKeyboardEdit->setChecked(false); + } +} + +void HexWidget::onKeyboardEditChanged(bool enabled) +{ + if (!enabled) { + finishEditingWord(); + navigationMode = HexNavigationMode::Words; + editWordState = EditWordState::Read; + } else { + editWordState = EditWordState::WriteNotStarted; + navigationMode = defaultNavigationMode(); + } + updateCursorMeta(); + viewport()->update(); +} + void HexWidget::updateItemLength() { itemPrefixLen = 0; + itemPrefix.clear(); switch (itemFormat) { case ItemFormatHex: itemCharLen = 2 * itemByteLen; - if (itemByteLen > 1 && showExHex) + if (itemByteLen > 1 && showExHex) { itemPrefixLen = hexPrefix.length(); + itemPrefix = hexPrefix; + } break; case ItemFormatOct: itemCharLen = (itemByteLen * 8 + 3) / 3; @@ -1056,7 +1612,13 @@ void HexWidget::drawCursor(QPainter &painter, bool shadow) QPen pen(Qt::gray); pen.setStyle(Qt::DashLine); painter.setPen(pen); - shadowCursor.screenPos.setWidth(cursorOnAscii ? itemWidth() : charWidth); + qreal shadowWidth = charWidth; + if (cursorOnAscii) { + shadowWidth = itemWidth(); + } else if (editWordState >= EditWordState::WriteNotEdited) { + shadowWidth = itemByteLen * charWidth; + } + shadowCursor.screenPos.setWidth(shadowWidth); painter.drawRect(shadowCursor.screenPos); painter.setPen(Qt::SolidLine); } @@ -1102,20 +1664,26 @@ void HexWidget::drawItemArea(QPainter &painter) fillSelectionBackground(painter); + bool haveEditWord = false; + QRectF editWordRect; + QColor editWordColor; + uint64_t itemAddr = startAddress; for (int line = 0; line < visibleLines; ++line) { itemRect.moveLeft(itemArea.left()); for (int j = 0; j < itemColumns; ++j) { for (int k = 0; k < itemGroupSize && itemAddr <= data->maxIndex(); ++k, itemAddr += itemByteLen) { + itemString = renderItem(itemAddr - startAddress, &itemColor); if (!getFlagsAndComment(itemAddr).isEmpty()) { QColor markerColor(borderColor); markerColor.setAlphaF(0.5); - const auto shape = rangePolygons(itemAddr, itemAddr, false)[0]; painter.setPen(markerColor); - painter.drawPolyline(shape); + for (const auto &shape : rangePolygons(itemAddr, itemAddr, false)) { + painter.drawPolyline(shape); + } } if (selection.contains(itemAddr) && !cursorOnAscii) { itemColor = palette().highlightedText().color(); @@ -1123,19 +1691,53 @@ void HexWidget::drawItemArea(QPainter &painter) if (isItemDifferentAt(itemAddr)) { itemColor.setRgb(diffColor.rgb()); } - painter.setPen(itemColor); - painter.drawText(itemRect, Qt::AlignVCenter, itemString); - itemRect.translate(itemWidth(), 0); - if (cursor.address == itemAddr) { - auto &itemCursor = cursorOnAscii ? shadowCursor : cursor; - itemCursor.cachedChar = itemString.at(0); + + if (editWordState <= EditWordState::WriteNotStarted || cursor.address != itemAddr) { + painter.setPen(itemColor); + painter.drawText(itemRect, Qt::AlignVCenter, itemString); + itemRect.translate(itemWidth(), 0); + if (cursor.address == itemAddr) { + auto &itemCursor = cursorOnAscii ? shadowCursor : cursor; + int itemCharPos = 0; + if (editWordState > EditWordState::Read) { + itemCharPos += itemPrefixLen; + } + if (itemCharPos < itemString.length()) { + itemCursor.cachedChar = itemString.at(itemCharPos); + } else { + itemCursor.cachedChar = ' '; + } + itemCursor.cachedColor = itemColor; + } + } else { + haveEditWord = true; + editWordRect = itemRect; + editWordColor = itemColor; + + auto &itemCursor = cursor; + itemCursor.cachedChar = + editWordPos < editWord.length() ? editWord[editWordPos] : QChar(' '); itemCursor.cachedColor = itemColor; + itemCursor.screenPos.moveTopLeft(itemRect.topLeft()); + itemCursor.screenPos.translate(charWidth * (editWordPos + itemPrefixLen), 0); + + itemRect.translate(itemWidth(), 0); } } itemRect.translate(columnSpacingWidth(), 0); } itemRect.translate(0, lineHeight); } + if (haveEditWord) { + auto length = std::max(itemCharLen, editWord.length()); + auto rect = editWordRect; + rect.setWidth(length * charWidth); + painter.fillRect(rect, backgroundColor); + + painter.setPen(editWordColor); + editWordRect.setWidth(4000); + painter.drawText(editWordRect, Qt::AlignVCenter | Qt::AlignLeft, itemPrefix + editWord); + } painter.setPen(borderColor); @@ -1222,12 +1824,16 @@ QVector HexWidget::rangePolygons(RVA start, RVA last, bool ascii) auto startRect = getRectangle(startOffset); auto endRect = getRectangle(endOffset); + bool startJagged = false; + bool endJagged = false; if (!ascii) { if (int startFraction = startOffset % itemByteLen) { startRect.setLeft(startRect.left() + startFraction * startRect.width() / itemByteLen); + startJagged = true; } if (int endFraction = itemByteLen - 1 - (endOffset % itemByteLen)) { endRect.setRight(endRect.right() - endFraction * endRect.width() / itemByteLen); + endJagged = true; } } if (endOffset - startOffset + 1 <= rowSizeBytes) { @@ -1263,6 +1869,33 @@ QVector HexWidget::rangePolygons(RVA start, RVA last, bool ascii) shape << shape.first(); // close the shape parts.push_back(shape); } + if (!ascii && (startJagged || endJagged) && parts.length() >= 1) { + + QPolygonF top; + top.reserve(3); + top << QPointF(0, 0) << QPointF(charWidth, lineHeight / 3) << QPointF(0, lineHeight / 2); + QPolygonF bottom; + bottom.reserve(3); + bottom << QPointF(0, lineHeight / 2) << QPointF(-charWidth, 2 * lineHeight / 3) + << QPointF(0, lineHeight); + + // small adjustment to make sure that edges don't overlap with rect edges, QPolygonF doesn't + // handle it properly + QPointF adjustment(charWidth / 16, 0); + top.translate(-adjustment); + bottom.translate(adjustment); + + if (startJagged) { + auto movedTop = top.translated(startRect.topLeft()); + auto movedBottom = bottom.translated(startRect.topLeft()); + parts[0] = parts[0].subtracted(movedTop).united(movedBottom); + } + if (endJagged) { + auto movedTop = top.translated(endRect.topRight()); + auto movedBottom = bottom.translated(endRect.topRight()); + parts.last() = parts.last().subtracted(movedBottom).united(movedTop); + } + } return parts; } @@ -1324,18 +1957,44 @@ void HexWidget::updateAreasHeight() asciiArea.setHeight(height); } -void HexWidget::moveCursor(int offset, bool select) +bool HexWidget::moveCursor(int offset, bool select, OverflowMove overflowMove) { - BasicCursor addr = cursor.address; - addr += offset; - if (addr.address > data->maxIndex()) { - addr.address = data->maxIndex(); + BasicCursor addr(cursor.address); + if (overflowMove == OverflowMove::Ignore) { + if (addr.moveChecked(offset)) { + if (addr.address > data->maxIndex()) { + addr.address = data->maxIndex(); + addr.pastEnd = true; + } + setCursorAddr(addr, select); + return true; + } + return false; + } else { + addr += offset; + if (addr.address > data->maxIndex()) { + addr.address = data->maxIndex(); + } + setCursorAddr(addr, select); + return true; + } +} + +void HexWidget::moveCursorKeepEditOffset(int byteOffset, bool select, OverflowMove overflowMove) +{ + int wordOffset = editWordPos; + moveCursor(byteOffset, select, overflowMove); + // preserve position within word when moving vertically in hex or oct modes + if (!cursorOnAscii && !select && wordOffset > 0 && navigationMode == HexNavigationMode::AnyChar + && editWordState > EditWordState::Read) { + startEditWord(); + editWordPos = wordOffset; } - setCursorAddr(addr, select); } void HexWidget::setCursorAddr(BasicCursor addr, bool select) { + finishEditingWord(); if (!select) { bool clearingSelection = !selection.isEmpty(); selection.init(addr); @@ -1345,6 +2004,9 @@ void HexWidget::setCursorAddr(BasicCursor addr, bool select) emit positionChanged(addr.address); cursor.address = addr.address; + if (!cursorOnAscii) { + cursor.address -= cursor.address % itemByteLen; + } /* Pause cursor repainting */ cursorEnabled = false; @@ -1361,7 +2023,9 @@ void HexWidget::setCursorAddr(BasicCursor addr, bool select) addressValue -= (addressValue % itemRowByteLen()); /* FIXME: handling Page Up/Down */ - if (addressValue == startAddress + bytesPerScreen()) { + uint64_t rowAfterVisibleAddress = startAddress + bytesPerScreen(); + if (addressValue == rowAfterVisibleAddress && addressValue > startAddress) { + // when pressing down add only one new row startAddress += itemRowByteLen(); } else { startAddress = addressValue; @@ -1410,6 +2074,10 @@ void HexWidget::updateCursorMeta() point += itemArea.topLeft(); pointAscii += asciiArea.topLeft(); + if (editWordState > EditWordState::Read && !cursorOnAscii) { + point.rx() += itemPrefixLen * charWidth; + } + cursor.screenPos.moveTopLeft(cursorOnAscii ? pointAscii : point); shadowCursor.screenPos.moveTopLeft(cursorOnAscii ? point : pointAscii); } @@ -1419,7 +2087,7 @@ void HexWidget::setCursorOnAscii(bool ascii) cursorOnAscii = ascii; } -const QColor HexWidget::itemColor(uint8_t byte) +QColor HexWidget::itemColor(uint8_t byte) { QColor color(defColor); @@ -1547,7 +2215,7 @@ QString HexWidget::renderItem(int offset, QColor *color) item = QString("%1").arg(itemVal.toLongLong(), itemLen, 10); break; case ItemFormatFloat: - item = QString("%1").arg(itemVal.toDouble(), itemLen); + item = QString("%1").arg(itemVal.toDouble(), itemLen, 'g', itemByteLen == 4 ? 6 : 15); break; } @@ -1588,13 +2256,191 @@ QString HexWidget::getFlagsAndComment(uint64_t address) return metaData; } +bool HexWidget::canKeyboardEdit() +{ + return ioModesController.canWrite() && actionKeyboardEdit->isChecked(); +} + +template +static bool checkRange(BigValue v) +{ + return v >= std::numeric_limits::min() && v <= std::numeric_limits::max(); +} + +template +static bool checkAndWrite(BigInteger value, uint8_t *buf, bool littleEndian) +{ + if (!checkRange(value)) { + return false; + } + if (littleEndian) { + qToLittleEndian((T)value, buf); + } else { + qToBigEndian((T)value, buf); + } + return true; +} + +template +static bool checkAndWriteWithSign(const QVariant &value, uint8_t *buf, bool isSigned, + bool littleEndian) +{ + if (isSigned) { + return checkAndWrite(value.toLongLong(), buf, littleEndian); + } else { + return checkAndWrite(value.toULongLong(), buf, littleEndian); + } +} + +bool HexWidget::parseWord(QString word, uint8_t *buf, size_t bufferSize) const +{ + bool parseOk = false; + if (bufferSize < size_t(itemByteLen)) { + return false; + } + if (itemFormat == ItemFormatFloat) { + if (itemByteLen == 4) { + float value = word.toFloat(&parseOk); + if (!parseOk) { + return false; + } + if (itemBigEndian) { + rz_write_be_float(buf, value); + } else { + rz_write_le_float(buf, value); + } + return true; + } else if (itemByteLen == 8) { + double value = word.toDouble(&parseOk); + if (!parseOk) { + return false; + } + if (itemBigEndian) { + rz_write_be_double(buf, value); + } else { + rz_write_le_double(buf, value); + } + return true; + } + return false; + } else { + QVariant value; + bool isSigned = false; + switch (itemFormat) { + case ItemFormatHex: + value = word.toULongLong(&parseOk, 16); + break; + case ItemFormatOct: + value = word.toULongLong(&parseOk, 8); + break; + case ItemFormatDec: + value = word.toULongLong(&parseOk, 10); + break; + case ItemFormatSignedDec: + isSigned = true; + value = word.toLongLong(&parseOk, 10); + break; + default: + break; + } + if (!parseOk) { + return false; + } + + switch (itemByteLen) { + case 1: + return checkAndWriteWithSign(value, buf, isSigned, !itemBigEndian); + case 2: + return checkAndWriteWithSign(value, buf, isSigned, !itemBigEndian); + case 4: + return checkAndWriteWithSign(value, buf, isSigned, !itemBigEndian); + case 8: + return checkAndWriteWithSign(value, buf, isSigned, !itemBigEndian); + } + } + return false; +} + +bool HexWidget::flushCurrentlyEditedWord() +{ + if (editWordState < EditWordState::WriteEdited) { + return true; + } + uint8_t buf[16]; + if (parseWord(editWord, buf, sizeof(buf))) { + data->write(buf, cursor.address, itemByteLen); + return true; + } + editWordState = EditWordState::WriteNotEdited; + return false; +} + +bool HexWidget::finishEditingWord(bool force) +{ + if (editWordState == EditWordState::WriteEdited) { + if (!flushCurrentlyEditedWord() && !force) { + qWarning() << "Not a valid number in current format or size" << editWord; + showWarningRect(itemRectangle(cursor.address - startAddress).adjusted(-1, -1, 1, 1)); + return false; + } + } + editWord.clear(); + editWordPos = 0; + editWordState = canKeyboardEdit() ? EditWordState::WriteNotStarted : EditWordState::Read; + navigationMode = defaultNavigationMode(); + return true; +} + +void HexWidget::cancelEditedWord() +{ + editWordPos = 0; + editWordState = canKeyboardEdit() ? EditWordState::WriteNotStarted : EditWordState::Read; + editWord.clear(); + navigationMode = defaultNavigationMode(); + updateCursorMeta(); + viewport()->update(); +} + +void HexWidget::maybeFlushCharEdit() +{ + if (editWordState < EditWordState::WriteEdited) { + return; + } + if ((itemFormat == ItemFormatHex && earlyEditFlush >= EarlyEditFlush::EditNibble) + || (isFixedWidth() && earlyEditFlush >= EarlyEditFlush::EditFixedWidthChar)) { + flushCurrentlyEditedWord(); + if (!flushCurrentlyEditedWord()) { + showWarningRect(itemRectangle(cursor.address - startAddress).adjusted(-1, -1, 1, 1)); + } + } + viewport()->update(); +} + +void HexWidget::startEditWord() +{ + if (!canKeyboardEdit()) { + return; + } + if (editWordState >= EditWordState::WriteNotEdited) { + return; + } + editWordPos = 0; + editWordState = EditWordState::WriteNotEdited; + navigationMode = defaultNavigationMode(); + editWord = renderItem(cursor.address - startAddress).trimmed(); + if (itemPrefixLen > 0) { + editWord = editWord.mid(itemPrefixLen); + } + viewport()->update(); +} + void HexWidget::fetchData() { data.swap(oldData); data->fetch(startAddress, bytesPerScreen()); } -BasicCursor HexWidget::screenPosToAddr(const QPoint &point, bool middle) const +BasicCursor HexWidget::screenPosToAddr(const QPoint &point, bool middle, int *wordOffset) const { QPointF pt = point - itemArea.topLeft(); @@ -1605,9 +2451,21 @@ BasicCursor HexWidget::screenPosToAddr(const QPoint &point, bool middle) const relativeAddress += column * itemGroupByteLen(); pt.rx() -= column * columnExWidth(); auto roundingOffset = middle ? itemWidth() / 2 : 0; - relativeAddress += static_cast((pt.x() + roundingOffset) / itemWidth()) * itemByteLen; + int posInGroup = static_cast((pt.x() + roundingOffset) / itemWidth()); + if (!middle) { + posInGroup = std::min(posInGroup, itemGroupSize - 1); + } + relativeAddress += posInGroup * itemByteLen; + pt.rx() -= posInGroup * itemWidth(); BasicCursor result(startAddress); result += relativeAddress; + + if (!middle && wordOffset != nullptr) { + int charPos = static_cast((pt.x() / charWidth) + 0.5); + charPos -= itemPrefixLen; + charPos = std::max(0, charPos); + *wordOffset = charPos; + } return result; } @@ -1679,3 +2537,17 @@ RVA HexWidget::getLocationAddress() { return !selection.isEmpty() ? selection.start() : cursor.address; } + +void HexWidget::hideWarningRect() +{ + warningRectVisible = false; + viewport()->update(); +} + +void HexWidget::showWarningRect(QRectF rect) +{ + warningRect = rect; + warningRectVisible = true; + warningTimer.start(WARNING_TIME_MS); + viewport()->update(); +} diff --git a/src/widgets/HexWidget.h b/src/widgets/HexWidget.h index b46f0574..103040c2 100644 --- a/src/widgets/HexWidget.h +++ b/src/widgets/HexWidget.h @@ -14,7 +14,7 @@ struct BasicCursor { uint64_t address; bool pastEnd; - BasicCursor(uint64_t pos) : address(pos), pastEnd(false) {} + explicit BasicCursor(uint64_t pos) : address(pos), pastEnd(false) {} BasicCursor() : address(0), pastEnd(false) {} BasicCursor &operator+=(int64_t offset) { @@ -35,6 +35,14 @@ struct BasicCursor *this += int64_t(offset); return *this; } + + bool moveChecked(int offset) + { + auto oldAddress = address; + *this += offset; + return address - oldAddress == uint64_t(offset); + } + BasicCursor &operator+=(uint64_t offset) { if (uint64_t(offset) > (UINT64_MAX - address)) { @@ -46,7 +54,10 @@ struct BasicCursor } return *this; } - bool operator<(const BasicCursor &r) { return address < r.address || (pastEnd < r.pastEnd); } + bool operator<(const BasicCursor &r) const + { + return address < r.address || (pastEnd < r.pastEnd); + } }; struct HexCursor @@ -74,9 +85,10 @@ struct HexCursor class AbstractData { public: - virtual ~AbstractData() {} + virtual ~AbstractData() = default; virtual void fetch(uint64_t addr, int len) = 0; virtual bool copy(void *out, uint64_t adr, size_t len) = 0; + virtual bool write(const uint8_t *in, uint64_t adr, size_t len) = 0; virtual uint64_t maxIndex() = 0; virtual uint64_t minIndex() = 0; }; @@ -86,7 +98,7 @@ class BufferData : public AbstractData public: BufferData() { m_buffer.fill(0, 1); } - BufferData(const QByteArray &buffer) + explicit BufferData(const QByteArray &buffer) { if (buffer.isEmpty()) { m_buffer.fill(0, 1); @@ -95,7 +107,7 @@ public: } } - ~BufferData() override {} + ~BufferData() override = default; void fetch(uint64_t, int) override {} @@ -109,6 +121,16 @@ public: return false; } + bool write(const uint8_t *in, uint64_t addr, size_t len) override + { + if (addr < static_cast(m_buffer.size()) + && (static_cast(m_buffer.size()) - addr) < len) { + memcpy(m_buffer.data() + addr, in, len); + return true; + } + return false; + } + uint64_t maxIndex() override { return m_buffer.size() - 1; } private: @@ -118,8 +140,8 @@ private: class MemoryData : public AbstractData { public: - MemoryData() {} - ~MemoryData() override {} + MemoryData() = default; + ~MemoryData() override = default; static constexpr size_t BLOCK_SIZE = 4096; void fetch(uint64_t address, int length) override @@ -144,10 +166,11 @@ public: bool copy(void *out, uint64_t addr, size_t len) override { - if (addr < m_firstBlockAddr || addr > m_lastValidAddr - || (m_lastValidAddr - addr + 1) - < len /* do not merge with last check to handle overflows */ - || m_blocks.isEmpty()) { + if (addr < m_firstBlockAddr + || addr > m_lastValidAddr + /* do not merge with previous check to handle overflows */ + || (m_lastValidAddr - addr + 1) < len || m_blocks.isEmpty()) { + memset(out, 0xff, len); return false; } @@ -165,9 +188,47 @@ public: return true; } - virtual uint64_t maxIndex() override { return m_lastValidAddr; } + void writeToCache(const uint8_t *in, uint64_t adr, size_t len) + { + if (adr < m_firstBlockAddr) { + uint64_t prefix = m_firstBlockAddr - adr; + if (prefix <= len) { + return; + } + in = in + prefix; + adr += prefix; + len -= prefix; + } + if (adr > m_lastValidAddr) { + return; + } + int offset = (int)(adr - m_firstBlockAddr); + int blockId = offset / BLOCK_SIZE; + int blockOffset = offset % BLOCK_SIZE; + while (len > 0 && blockId < m_blocks.size()) { + size_t l = BLOCK_SIZE - blockOffset; + l = std::min(l, len); + memcpy(m_blocks[blockId].data() + blockOffset, in, l); + len -= l; + blockOffset = 0; + adr += l; + in += l; + blockId += 1; + } + } - virtual uint64_t minIndex() override { return m_firstBlockAddr; } + bool write(const uint8_t *in, uint64_t adr, size_t len) override + { + RzCoreLocked core(Core()); + rz_core_write_at(core, adr, in, len); + writeToCache(in, adr, len); + emit Core()->instructionChanged(adr); + return true; + } + + uint64_t maxIndex() override { return std::numeric_limits::max(); } + + uint64_t minIndex() override { return m_firstBlockAddr; } private: QVector m_blocks; @@ -178,7 +239,11 @@ private: class HexSelection { public: - HexSelection() { m_empty = true; } + HexSelection() + { + m_empty = true; + m_start = m_end = 0; + } inline void init(BasicCursor addr) { @@ -189,7 +254,8 @@ public: void set(uint64_t start, uint64_t end) { m_empty = false; - m_init = m_start = start; + m_init = BasicCursor(start); + m_start = start; m_end = end; } @@ -219,7 +285,7 @@ public: bool contains(uint64_t pos) const { return !m_empty && m_start <= pos && pos <= m_end; } - uint64_t size() + uint64_t size() const { uint64_t size = 0; if (!isEmpty()) @@ -227,9 +293,9 @@ public: return size; } - inline bool isEmpty() { return m_empty; } - inline uint64_t start() { return m_start; } - inline uint64_t end() { return m_end; } + inline bool isEmpty() const { return m_empty; } + inline uint64_t start() const { return m_start; } + inline uint64_t end() const { return m_end; } private: BasicCursor m_init; @@ -244,7 +310,7 @@ class HexWidget : public QScrollArea public: explicit HexWidget(QWidget *parent = nullptr); - ~HexWidget(); + ~HexWidget() override = default; void setMonospaceFont(const QFont &font); @@ -258,10 +324,12 @@ public: ItemFormatFloat }; enum class ColumnMode { Fixed, PowerOf2 }; + enum class EditWordState { Read, WriteNotStarted, WriteNotEdited, WriteEdited }; + enum class HexNavigationMode { Words, WordChar, AnyChar }; void setItemSize(int nbytes); void setItemFormat(ItemFormat format); - void setItemEndianess(bool bigEndian); + void setItemEndianness(bool bigEndian); void setItemGroupSize(int size); /** * @brief Sets line size in bytes. @@ -292,7 +360,7 @@ public slots: void refresh(); void updateColors(); signals: - void selectionChanged(Selection selection); + void selectionChanged(HexWidget::Selection selection); void positionChanged(RVA start); protected: @@ -300,10 +368,12 @@ protected: void resizeEvent(QResizeEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; void wheelEvent(QWheelEvent *event) override; void keyPressEvent(QKeyEvent *event) override; void contextMenuEvent(QContextMenuEvent *event) override; + bool event(QEvent *event) override; private slots: void onCursorBlinked(); @@ -311,13 +381,13 @@ private slots: void copy(); void copyAddress(); void onRangeDialogAccepted(); - void on_actionAddComment_triggered(); - void on_actionDeleteComment_triggered(); + void onActionAddCommentTriggered(); + void onActionDeleteCommentTriggered(); // Write command slots void w_writeString(); void w_increaseDecrease(); - void w_writeBytes(); + void w_writeBytes(); void w_writeZeros(); void w_write64(); void w_writeRandom(); @@ -326,6 +396,9 @@ private slots: void w_writeWideString(); void w_writeCString(); + void onKeyboardEditTriggered(bool enabled); + void onKeyboardEditChanged(bool enabled); + private: void updateItemLength(); void updateCounts(); @@ -338,12 +411,15 @@ private: void updateMetrics(); void updateAreasPosition(); void updateAreasHeight(); - void moveCursor(int offset, bool select = false); + enum class OverflowMove { Clamp, Ignore }; + bool moveCursor(int offset, bool select = false, + OverflowMove overflowMove = OverflowMove::Clamp); + void moveCursorKeepEditOffset(int byteOffset, bool select, OverflowMove overflowMove); void setCursorAddr(BasicCursor addr, bool select = false); void updateCursorMeta(); void setCursorOnAscii(bool ascii); bool isItemDifferentAt(uint64_t address); - const QColor itemColor(uint8_t byte); + QColor itemColor(uint8_t byte); QVariant readItem(int offset, QColor *color = nullptr); QString renderItem(int offset, QColor *color = nullptr); QChar renderAscii(int offset, QColor *color = nullptr); @@ -359,12 +435,13 @@ private: /** * @brief Convert mouse position to address. * @param point mouse position in widget - * @param middle start next position from middle of symbol. Use middle=true for vertical cursror + * @param middle start next position from middle of symbol. Use middle=true for vertical cursor * position between symbols, middle=false for insert mode cursor and getting symbol under * cursor. * @return */ - BasicCursor screenPosToAddr(const QPoint &point, bool middle = false) const; + BasicCursor screenPosToAddr(const QPoint &point, bool middle = false, + int *wordOffset = nullptr) const; BasicCursor asciiPosToAddr(const QPoint &point, bool middle = false) const; BasicCursor currentAreaPosToAddr(const QPoint &point, bool middle = false) const; BasicCursor mousePosToAddr(const QPoint &point, bool middle = false) const; @@ -412,6 +489,27 @@ private: inline uint64_t lastVisibleAddr() const { return (startAddress - 1) + bytesPerScreen(); } const QRectF ¤tArea() const { return cursorOnAscii ? asciiArea : itemArea; } + bool isFixedWidth() const; + + bool canKeyboardEdit(); + bool flushCurrentlyEditedWord(); + bool finishEditingWord(bool force = true); + void maybeFlushCharEdit(); + void cancelEditedWord(); + void startEditWord(); + bool validCharForEdit(QChar digit); + void movePrevEditCharAny(); + void typeOverwriteModeChar(QChar c); + HexNavigationMode defaultNavigationMode(); + void refreshWordEditState(); + bool parseWord(QString word, uint8_t *buf, size_t bufferSize) const; + bool handleAsciiWrite(QKeyEvent *event); + bool handleNumberWrite(QKeyEvent *event); + + void writeZeros(uint64_t address, uint64_t length); + + void hideWarningRect(); + void showWarningRect(QRectF rect); bool cursorEnabled; bool cursorOnAscii; @@ -436,14 +534,13 @@ private: ItemFormat itemFormat; bool itemBigEndian; + QString itemPrefix; int visibleLines; uint64_t startAddress; qreal charWidth; - int byteWidth; qreal lineHeight; int addrCharLen; - int addrAreaWidth; QFont monospaceFont; bool showHeader; @@ -460,6 +557,7 @@ private: QColor b0x7fColor; QColor b0xffColor; QColor printableColor; + QColor warningColor; HexdumpRangeDialog rangeDialog; @@ -479,14 +577,30 @@ private: QAction *actionCopyAddress; QAction *actionComment; QAction *actionDeleteComment; - QAction *actionSetFlag; QAction *actionSelectRange; + QAction *actionKeyboardEdit; QList actionsWriteString; QList actionsWriteOther; std::unique_ptr oldData; std::unique_ptr data; IOModesController ioModesController; + + int editWordPos = 0; + QString editWord; + EditWordState editWordState = EditWordState::Read; + HexNavigationMode navigationMode = HexNavigationMode::Words; + enum class EarlyEditFlush { + OnFinish, + EditNibble, + EditFixedWidthChar, + /* AllFormats(not implemented) */ + }; + EarlyEditFlush earlyEditFlush = EarlyEditFlush::EditFixedWidthChar; + + bool warningRectVisible = false; + QRectF warningRect; + QTimer warningTimer; }; #endif // HEXWIDGET_H From d972f86e6f834f4fc7f7693a7063c7e4c57a45d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 19 Sep 2022 09:47:22 +0200 Subject: [PATCH 162/240] Bump version to 2.1.2 (#3039) --- .appveyor.yml | 2 +- CMakeLists.txt | 2 +- docs/source/conf.py | 2 +- src/re.rizin.cutter.appdata.xml | 2 ++ 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 84a3b615..dc3f82d3 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -version: '2.1.0-git-{build}' +version: '2.1.2-git-{build}' image: 'Visual Studio 2017' clone_depth: 1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 9b9a9828..e7f950f2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ endif() set(CUTTER_VERSION_MAJOR 2) set(CUTTER_VERSION_MINOR 1) -set(CUTTER_VERSION_PATCH 0) +set(CUTTER_VERSION_PATCH 2) set(CUTTER_VERSION_FULL "${CUTTER_VERSION_MAJOR}.${CUTTER_VERSION_MINOR}.${CUTTER_VERSION_PATCH}") diff --git a/docs/source/conf.py b/docs/source/conf.py index b2677d68..640b7f9b 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -26,7 +26,7 @@ author = 'The Cutter Developers' # The short X.Y version version = '2.1' # The full version, including a2lpha/beta/rc tags -release = '2.1.0' +release = '2.1.2' # -- General configuration --------------------------------------------------- diff --git a/src/re.rizin.cutter.appdata.xml b/src/re.rizin.cutter.appdata.xml index c28c481c..e8e0de5e 100644 --- a/src/re.rizin.cutter.appdata.xml +++ b/src/re.rizin.cutter.appdata.xml @@ -25,6 +25,8 @@ xarkes + + From 8ad700a6dc1a4a628f23ebefa2138c5f8df0182d Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Wed, 5 Oct 2022 04:35:43 +0200 Subject: [PATCH 163/240] Update rizin (#3044) --- rizin | 2 +- src/core/Cutter.cpp | 8 ++------ 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/rizin b/rizin index 32ef1713..fbad0b48 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 32ef171354e2fde6194a354a1a350df357c08afc +Subproject commit fbad0b4859802a62dcc96002c2710e696809a0c3 diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 513806ff..04467ae2 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3051,12 +3051,8 @@ QList CutterCore::getAllFunctions() FunctionDescription function; function.offset = fcn->addr; function.linearSize = rz_analysis_function_linear_size(fcn); - function.nargs = rz_analysis_var_count(core->analysis, fcn, 'b', 1) - + rz_analysis_var_count(core->analysis, fcn, 'r', 1) - + rz_analysis_var_count(core->analysis, fcn, 's', 1); - function.nlocals = rz_analysis_var_count(core->analysis, fcn, 'b', 0) - + rz_analysis_var_count(core->analysis, fcn, 'r', 0) - + rz_analysis_var_count(core->analysis, fcn, 's', 0); + function.nargs = rz_analysis_var_count_total(fcn, RZ_ANALYSIS_VAR_TYPE_ARGUMENT); + function.nlocals = rz_analysis_var_count_total(fcn, RZ_ANALYSIS_VAR_TYPE_LOCAL); function.nbbs = rz_list_length(fcn->bbs); function.calltype = fcn->cc ? QString::fromUtf8(fcn->cc) : QString(); function.name = fcn->name ? QString::fromUtf8(fcn->name) : QString(); From 0624cd1d19d1a5fb475683b128699383a958691f Mon Sep 17 00:00:00 2001 From: Duncan Ogilvie Date: Sun, 23 Oct 2022 13:40:26 +0200 Subject: [PATCH 164/240] Show a nice folder structure in Visual Studio (#2890) --- CMakeLists.txt | 6 ++++++ src/CMakeLists.txt | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e7f950f2..3c615e56 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,6 +43,12 @@ set(CUTTER_VERSION_FULL "${CUTTER_VERSION_MAJOR}.${CUTTER_VERSION_MINOR}.${CUTTE project(Cutter VERSION "${CUTTER_VERSION_FULL}") +# Enable solution folder support +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +# Put Qt files in a separate folder +set_property(GLOBAL PROPERTY AUTOGEN_SOURCE_GROUP "Generated Files") + set(CMAKE_CXX_STANDARD 11) include(CutterInstallDirs) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 9b606132..e3c2c97d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -442,8 +442,11 @@ if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" set_source_files_properties(${BINDINGS_SOURCE} PROPERTIES COMPILE_FLAGS -w) endif() +# Make a source group for Visual Studio +set(CUTTER_SOURCES ${OPTIONS} ${UI_FILES} ${QRC_FILES} ${PLATFORM_RESOURCES} ${SOURCES} ${HEADER_FILES}) +source_group(TREE "${CMAKE_CURRENT_LIST_DIR}" FILES ${CUTTER_SOURCES}) -add_executable(Cutter ${OPTIONS} ${UI_FILES} ${QRC_FILES} ${PLATFORM_RESOURCES} ${SOURCES} ${HEADER_FILES} ${BINDINGS_SOURCE}) +add_executable(Cutter ${CUTTER_SOURCES} ${BINDINGS_SOURCE}) set_target_properties(Cutter PROPERTIES OUTPUT_NAME cutter RUNTIME_OUTPUT_DIRECTORY .. @@ -452,6 +455,9 @@ set_target_properties(Cutter PROPERTIES CXX_VISIBILITY_PRESET hidden) target_compile_definitions(Cutter PRIVATE CUTTER_SOURCE_BUILD) +# Set Cutter as the startup project in Visual Studio +set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Cutter) + set(CUTTER_INCLUDE_DIRECTORIES core widgets common plugins menus .) foreach(_dir ${CUTTER_INCLUDE_DIRECTORIES}) target_include_directories(Cutter PUBLIC From 3224daa0eefef7e2f5e52b49ae6d0a47d33280a3 Mon Sep 17 00:00:00 2001 From: Alex Anderson Date: Sun, 23 Oct 2022 04:43:30 -0700 Subject: [PATCH 165/240] Add case insensitive string search (#2817) --- src/widgets/SearchWidget.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/widgets/SearchWidget.cpp b/src/widgets/SearchWidget.cpp index fc5e5d43..0fcb9f8e 100644 --- a/src/widgets/SearchWidget.cpp +++ b/src/widgets/SearchWidget.cpp @@ -254,6 +254,7 @@ void SearchWidget::refreshSearchspaces() ui->searchspaceCombo->clear(); ui->searchspaceCombo->addItem(tr("asm code"), QVariant("/acj")); ui->searchspaceCombo->addItem(tr("string"), QVariant("/j")); + ui->searchspaceCombo->addItem(tr("string (case insensitive)"), QVariant("/ij")); ui->searchspaceCombo->addItem(tr("hex string"), QVariant("/xj")); ui->searchspaceCombo->addItem(tr("ROP gadgets"), QVariant("/Rj")); ui->searchspaceCombo->addItem(tr("32bit value"), QVariant("/vj")); @@ -301,13 +302,16 @@ void SearchWidget::updatePlaceholderText(int index) case 1: // string ui->filterLineEdit->setPlaceholderText("foobar"); break; - case 2: // hex string + case 2: // string (case insensitive) + ui->filterLineEdit->setPlaceholderText("FooBar"); + break; + case 3: // hex string ui->filterLineEdit->setPlaceholderText("deadbeef"); break; - case 3: // ROP gadgets + case 4: // ROP gadgets ui->filterLineEdit->setPlaceholderText("pop,,pop"); break; - case 4: // 32bit value + case 5: // 32bit value ui->filterLineEdit->setPlaceholderText("0xdeadbeef"); break; default: From 1ac814c1b9394a9c03f76a915b48462d2dff8e51 Mon Sep 17 00:00:00 2001 From: Duncan Ogilvie Date: Tue, 25 Oct 2022 12:16:48 +0200 Subject: [PATCH 166/240] Fix the padding in SimpleTextGraphView (#3046) --- src/widgets/SimpleTextGraphView.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/widgets/SimpleTextGraphView.cpp b/src/widgets/SimpleTextGraphView.cpp index ad4c5deb..feebdd4c 100644 --- a/src/widgets/SimpleTextGraphView.cpp +++ b/src/widgets/SimpleTextGraphView.cpp @@ -119,8 +119,8 @@ void SimpleTextGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block, b p.setPen(palette().color(QPalette::WindowText)); // Render node text - auto x = block.x + padding; - int y = block.y + padding + p.fontMetrics().ascent(); + auto x = block.x + padding / 2; + int y = block.y + padding / 2 + p.fontMetrics().ascent(); p.drawText(QPoint(x, y), content.text); } From ae1e15b7a2ed74b474b1f0fb72acccb25cffdb3a Mon Sep 17 00:00:00 2001 From: Theofilos Pechlivanis Date: Sat, 29 Oct 2022 21:57:30 +0300 Subject: [PATCH 167/240] Keep CallGraph widget active when seeking to other functions --- src/core/MainWindow.cpp | 6 ++++++ src/widgets/CallGraph.cpp | 9 +++++++-- src/widgets/CallGraph.h | 6 ++++-- src/widgets/MemoryDockWidget.h | 2 +- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index 6a840fcc..46c6fac0 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -1086,6 +1086,12 @@ MemoryDockWidget *MainWindow::addNewMemoryWidget(MemoryWidgetType type, RVA addr case MemoryWidgetType::Decompiler: memoryWidget = new DecompilerWidget(this); break; + case MemoryWidgetType::CallGraph: + memoryWidget = new CallGraphWidget(this, false); + break; + case MemoryWidgetType::GlobalCallGraph: + memoryWidget = new CallGraphWidget(this, true); + break; } auto seekable = memoryWidget->getSeekable(); seekable->setSynchronization(synchronized); diff --git a/src/widgets/CallGraph.cpp b/src/widgets/CallGraph.cpp index 8c3d7e4a..64736573 100644 --- a/src/widgets/CallGraph.cpp +++ b/src/widgets/CallGraph.cpp @@ -7,9 +7,9 @@ #include CallGraphWidget::CallGraphWidget(MainWindow *main, bool global) - : AddressableDockWidget(main), graphView(new CallGraphView(this, main, global)), global(global) + : MemoryDockWidget(MemoryWidgetType::CallGraph, main), graphView(new CallGraphView(this, main, global)), global(global) { - setObjectName(main->getUniqueObjectName("CallGraphWidget")); + setObjectName(main ? main->getUniqueObjectName(getWidgetType()) : getWidgetType()); this->setWindowTitle(getWindowTitle()); connect(seekable, &CutterSeekable::seekableSeekChanged, this, &CallGraphWidget::onSeekChanged); @@ -23,6 +23,11 @@ QString CallGraphWidget::getWindowTitle() const return global ? tr("Global Callgraph") : tr("Callgraph"); } +QString CallGraphWidget::getWidgetType() const +{ + return global ? tr("GlobalCallgraph") : tr("Callgraph"); +} + void CallGraphWidget::onSeekChanged(RVA address) { if (auto function = Core()->functionIn(address)) { diff --git a/src/widgets/CallGraph.h b/src/widgets/CallGraph.h index 2d348266..2c6e0a96 100644 --- a/src/widgets/CallGraph.h +++ b/src/widgets/CallGraph.h @@ -2,7 +2,7 @@ #define CALL_GRAPH_WIDGET_H #include "core/Cutter.h" -#include "AddressableDockWidget.h" +#include "MemoryDockWidget.h" #include "widgets/SimpleTextGraphView.h" #include "common/RefreshDeferrer.h" @@ -30,7 +30,7 @@ private: RVA lastLoadedAddress = RVA_INVALID; }; -class CallGraphWidget : public AddressableDockWidget +class CallGraphWidget : public MemoryDockWidget { Q_OBJECT @@ -38,6 +38,8 @@ public: explicit CallGraphWidget(MainWindow *main, bool global); ~CallGraphWidget(); + QString getWidgetType() const; + protected: QString getWindowTitle() const override; diff --git a/src/widgets/MemoryDockWidget.h b/src/widgets/MemoryDockWidget.h index 51d0ca88..0b1a5952 100644 --- a/src/widgets/MemoryDockWidget.h +++ b/src/widgets/MemoryDockWidget.h @@ -7,7 +7,7 @@ #include /* Disassembly/Graph/Hexdump/Decompiler view priority */ -enum class MemoryWidgetType { Disassembly, Graph, Hexdump, Decompiler }; +enum class MemoryWidgetType { Disassembly, Graph, Hexdump, Decompiler, CallGraph, GlobalCallGraph }; class CUTTER_EXPORT MemoryDockWidget : public AddressableDockWidget { From 22e8bf23819a3305292331aa9e030d18c7af81c2 Mon Sep 17 00:00:00 2001 From: Theofilos Pechlivanis <49034471+theopechli@users.noreply.github.com> Date: Tue, 1 Nov 2022 22:01:56 +0200 Subject: [PATCH 168/240] Refresh Call Graph when renaming functions (#3049) --- src/widgets/CallGraph.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/widgets/CallGraph.cpp b/src/widgets/CallGraph.cpp index 64736573..001844d0 100644 --- a/src/widgets/CallGraph.cpp +++ b/src/widgets/CallGraph.cpp @@ -42,6 +42,7 @@ CallGraphView::CallGraphView(CutterDockWidget *parent, MainWindow *main, bool gl refreshDeferrer.registerFor(parent); connect(&refreshDeferrer, &RefreshDeferrer::refreshNow, this, &CallGraphView::refreshView); connect(Core(), &CutterCore::refreshAll, this, &SimpleTextGraphView::refreshView); + connect(Core(), &CutterCore::functionRenamed, this, &CallGraphView::refreshView); } void CallGraphView::showExportDialog() From e7c9ab515e71dd240d1be9c9dee0ab69f8af176f Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 2 Nov 2022 18:14:23 +0800 Subject: [PATCH 169/240] Update Rizin to the latest `dev` (#3050) * Update Rizin * Remove rz-agent from CMake scripts --- cmake/BundledRizin.cmake | 2 +- rizin | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index 0a3c4491..c6982838 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -63,7 +63,7 @@ set (RZ_LIBS rz_core rz_config rz_cons rz_io rz_util rz_flag rz_asm rz_debug rz_search rz_syscall rz_socket rz_magic rz_crypto rz_type rz_diff rz_sign rz_demangler) set (RZ_EXTRA_LIBS rz_main) -set (RZ_BIN rz-agent rz-bin rizin rz-diff rz-find rz-gg rz-hash rz-run rz-asm rz-ax) +set (RZ_BIN rz-bin rizin rz-diff rz-find rz-gg rz-hash rz-run rz-asm rz-ax) target_link_libraries(Rizin INTERFACE ${RZ_LIBS}) diff --git a/rizin b/rizin index fbad0b48..b59d9a03 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit fbad0b4859802a62dcc96002c2710e696809a0c3 +Subproject commit b59d9a03b2618d7209925da2a7873b40972f42a4 From e56a0b55812cd8d8d30cd74f86ca1a4c5caf36f8 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 2 Nov 2022 19:13:57 +0800 Subject: [PATCH 170/240] Fix GitHub Actions warnings (#3051) --- .github/workflows/ci.yml | 6 +++--- .github/workflows/coverity-scan.yml | 8 ++++---- .github/workflows/docs.yml | 4 ++-- .github/workflows/linter.yml | 4 ++-- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index edd72529..36ff9aa6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,7 +61,7 @@ jobs: # Prevent one job from pausing the rest fail-fast: false steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive persist-credentials: false @@ -79,7 +79,7 @@ jobs: then sudo apt-get install qt5-default libqt5svg5-dev qttools5-dev qttools5-dev-tools fi - - uses: actions/setup-python@v1 + - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - name: homebrew dependencies @@ -276,7 +276,7 @@ jobs: echo PACKAGE_NAME=Cutter-${PACKAGE_ID}-src.tar.gz >> $GITHUB_ENV echo PACKAGE_PATH=Cutter-${PACKAGE_ID}-src.tar.gz >> $GITHUB_ENV echo UPLOAD_ASSET_TYPE=application/gzip >> $GITHUB_ENV - - uses: actions/upload-artifact@v2 + - uses: actions/upload-artifact@v3 if: env.PACKAGE_NAME != null with: name: ${{ env.PACKAGE_NAME }} diff --git a/.github/workflows/coverity-scan.yml b/.github/workflows/coverity-scan.yml index 4672244b..66742428 100644 --- a/.github/workflows/coverity-scan.yml +++ b/.github/workflows/coverity-scan.yml @@ -7,16 +7,16 @@ jobs: latest: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - - uses: actions/setup-python@v1 + - uses: actions/setup-python@v4 with: - python-version: 3.7.x + python-version: 3.9.x - name: Download Coverity Build Tool run: | - wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=radareorg%2Fcutter" -O cov-analysis-linux64.tar.gz + wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=rizinorg%2Fcutter" -O cov-analysis-linux64.tar.gz mkdir cov-analysis-linux64 tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64 env: diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index a423c001..09929175 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -7,9 +7,9 @@ on: jobs: deploy: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - name: install dependencies diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index dfe70b68..c9488b8e 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -16,7 +16,7 @@ jobs: outputs: clang-format: ${{ steps.filter.outputs.clang-format }} steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: dorny/paths-filter@v2 id: filter with: @@ -33,7 +33,7 @@ jobs: if: ${{ needs.changes.outputs.clang-format == 'true' }} steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Install wget run: sudo apt --assume-yes install wget From dda1ece261e8c20c612ca449e96ada4644b89cff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Fri, 4 Nov 2022 15:17:23 +0100 Subject: [PATCH 171/240] Remove use of deprecated rz_analysis_var_all_list() (#3052) --- src/core/Cutter.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 04467ae2..696cea7f 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3966,8 +3966,7 @@ QList CutterCore::getXRefsForVariable(QString variableName, boo const auto typ = findWrites ? RZ_ANALYSIS_VAR_ACCESS_TYPE_WRITE : RZ_ANALYSIS_VAR_ACCESS_TYPE_READ; QList xrefList = QList(); - RzList *vars = rz_analysis_var_all_list(core->analysis, fcn); - for (const auto &v : CutterRzList(vars)) { + for (const auto &v : CutterPVector(&fcn->vars)) { if (variableName != v->name) { continue; } From abfcad65848af5af7c448b866ea65563fec5fe00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 5 Nov 2022 00:13:02 +0100 Subject: [PATCH 172/240] Update rizin with new var counting functions (#3053) --- rizin | 2 +- src/core/Cutter.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rizin b/rizin index b59d9a03..3f077bce 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit b59d9a03b2618d7209925da2a7873b40972f42a4 +Subproject commit 3f077bce4a0a7c6323b31d06c6a3a631a988fa5f diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 696cea7f..ce9d4cdb 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3051,8 +3051,8 @@ QList CutterCore::getAllFunctions() FunctionDescription function; function.offset = fcn->addr; function.linearSize = rz_analysis_function_linear_size(fcn); - function.nargs = rz_analysis_var_count_total(fcn, RZ_ANALYSIS_VAR_TYPE_ARGUMENT); - function.nlocals = rz_analysis_var_count_total(fcn, RZ_ANALYSIS_VAR_TYPE_LOCAL); + function.nargs = rz_analysis_arg_count(fcn); + function.nlocals = rz_analysis_var_local_count(fcn); function.nbbs = rz_list_length(fcn->bbs); function.calltype = fcn->cc ? QString::fromUtf8(fcn->cc) : QString(); function.name = fcn->name ? QString::fromUtf8(fcn->name) : QString(); From 22613b52ede90750bbc68f5431a88380d4945505 Mon Sep 17 00:00:00 2001 From: Paula Date: Sun, 6 Nov 2022 07:32:30 +0100 Subject: [PATCH 173/240] Adding some functions to "banned" (#2816) --- src/widgets/ImportsWidget.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/widgets/ImportsWidget.h b/src/widgets/ImportsWidget.h index 85819bf5..9972b3a6 100644 --- a/src/widgets/ImportsWidget.h +++ b/src/widgets/ImportsWidget.h @@ -28,6 +28,7 @@ private: const QRegularExpression banned = QRegularExpression( QStringLiteral("\\A(\\w\\.)*(system|strcpy|strcpyA|strcpyW|wcscpy|_tcscpy|_mbscpy|" "StrCpy|StrCpyA|StrCpyW|lstrcpy|lstrcpyA|lstrcpyW" + "DCIEnum|DCIOpenProvider|DCISendCommand|DCIBeginAccess" "|_tccpy|_mbccpy|_ftcscpy|strcat|strcatA|strcatW|wcscat|_tcscat|_mbscat|" "StrCat|StrCatA|StrCatW|lstrcat|lstrcatA|" "lstrcatW|StrCatBuff|StrCatBuffA|StrCatBuffW|StrCatChainW|_tccat|_" @@ -51,7 +52,7 @@ private: "ui64tow|_ultoa|_ultot|_ultow|CharToOem|CharToOemA|CharToOemW|" "OemToChar|OemToCharA|OemToCharW|CharToOemBuffA|CharToOemBuffW|alloca|_" "alloca|strlen|wcslen|_mbslen|_mbstrlen|StrLen|lstrlen|" - "ChangeWindowMessageFilter)\\z")); + "ChangeWindowMessageFilter|ChangeWindowMessageFilterEx)\\z")); QList imports; public: From d58edca0c858e96fd75ae22627e86eaec09de588 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Fri, 25 Nov 2022 15:53:10 +0100 Subject: [PATCH 174/240] Fix wrong tg link in new issue (#3057) --- .github/ISSUE_TEMPLATE/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index b54d7076..acc7e264 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -2,9 +2,9 @@ blank_issues_enabled: false contact_links: - name: Questions Telegram - url: https://t.me/r2cutter + url: https://t.me/cutter_re about: Please ask questions about Cutter here or one of the other community channels, not in the issue tracker. - name: Questions IRC url: https://web.libera.chat/#cutter - about: "#cutter on https://web.libera.chat/" \ No newline at end of file + about: "#cutter on https://web.libera.chat/" From d47eb1c41fed647e453f81aa6e38961440a61084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 2 Jan 2023 13:29:41 +0100 Subject: [PATCH 175/240] Update to new variable storage in Rizin (#3062) --- rizin | 2 +- src/core/Cutter.cpp | 13 +------------ src/core/CutterDescriptions.h | 3 +-- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/rizin b/rizin index 3f077bce..d9950f74 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 3f077bce4a0a7c6323b31d06c6a3a631a988fa5f +Subproject commit d9950f74792c1dfb565ac491cc7ef706b80e6044 diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index ce9d4cdb..b21a1e03 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1793,18 +1793,7 @@ QList CutterCore::getVariables(RVA at) } for (auto var : CutterPVector(&fcn->vars)) { VariableDescription desc; - switch (var->kind) { - case RZ_ANALYSIS_VAR_KIND_BPV: - desc.refType = VariableDescription::RefType::BP; - break; - case RZ_ANALYSIS_VAR_KIND_SPV: - desc.refType = VariableDescription::RefType::SP; - break; - case RZ_ANALYSIS_VAR_KIND_REG: - default: - desc.refType = VariableDescription::RefType::Reg; - break; - } + desc.storageType = var->storage.type; if (!var->name || !var->type) { continue; } diff --git a/src/core/CutterDescriptions.h b/src/core/CutterDescriptions.h index a56f7186..aed9b508 100644 --- a/src/core/CutterDescriptions.h +++ b/src/core/CutterDescriptions.h @@ -355,8 +355,7 @@ struct RefDescription struct VariableDescription { - enum class RefType { SP, BP, Reg }; - RefType refType; + RzAnalysisVarStorageType storageType; QString name; QString type; }; From 2d7fd02a62dd3405d5405a997a8263c6e7706d67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Wed, 4 Jan 2023 18:23:07 +0100 Subject: [PATCH 176/240] Unify parents of dialogs shown by DecompilerContextMenu (#3066) When triggered through a keyboard shortcut, the dialogs shown here would be positioned at the last position of the context menu or (0, 0), which is not desired. Using a currently shown widget as the parent fixes this. --- src/menus/DecompilerContextMenu.cpp | 29 ++++++++++++++++++----------- src/menus/DecompilerContextMenu.h | 6 ++++++ 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/menus/DecompilerContextMenu.cpp b/src/menus/DecompilerContextMenu.cpp index 7113ec68..2dd6907a 100644 --- a/src/menus/DecompilerContextMenu.cpp +++ b/src/menus/DecompilerContextMenu.cpp @@ -69,6 +69,11 @@ DecompilerContextMenu::DecompilerContextMenu(QWidget *parent, MainWindow *mainWi DecompilerContextMenu::~DecompilerContextMenu() {} +QWidget *DecompilerContextMenu::parentForDialog() +{ + return parentWidget(); +} + void DecompilerContextMenu::setAnnotationHere(RzCodeAnnotation *annotation) { annotationHere = annotation; @@ -404,14 +409,15 @@ void DecompilerContextMenu::actionRenameThingHereTriggered() RzAnalysisFunction *func = Core()->functionAt(func_addr); if (func == NULL) { QString function_name = QInputDialog::getText( - this, tr("Define this function at %2").arg(RzAddressString(func_addr)), + parentForDialog(), + tr("Define this function at %2").arg(RzAddressString(func_addr)), tr("Function name:"), QLineEdit::Normal, currentName, &ok); if (ok && !function_name.isEmpty()) { Core()->createFunctionAt(func_addr, function_name); } } else { QString newName = QInputDialog::getText( - this->mainWindow, tr("Rename function %2").arg(currentName), + parentForDialog(), tr("Rename function %2").arg(currentName), tr("Function name:"), QLineEdit::Normal, currentName, &ok); if (ok && !newName.isEmpty()) { Core()->renameFunction(func_addr, newName); @@ -421,16 +427,16 @@ void DecompilerContextMenu::actionRenameThingHereTriggered() RVA var_addr = annotationHere->reference.offset; RzFlagItem *flagDetails = rz_flag_get_i(core->flags, var_addr); if (flagDetails) { - QString newName = QInputDialog::getText(this, tr("Rename %2").arg(flagDetails->name), - tr("Enter name"), QLineEdit::Normal, - flagDetails->name, &ok); + QString newName = QInputDialog::getText( + parentForDialog(), tr("Rename %2").arg(flagDetails->name), tr("Enter name"), + QLineEdit::Normal, flagDetails->name, &ok); if (ok && !newName.isEmpty()) { Core()->renameFlag(flagDetails->name, newName); } } else { QString newName = QInputDialog::getText( - this, tr("Add name to %2").arg(curHighlightedWord), tr("Enter name"), - QLineEdit::Normal, curHighlightedWord, &ok); + parentForDialog(), tr("Add name to %2").arg(curHighlightedWord), + tr("Enter name"), QLineEdit::Normal, curHighlightedWord, &ok); if (ok && !newName.isEmpty()) { Core()->addFlag(var_addr, newName, 1); } @@ -439,14 +445,14 @@ void DecompilerContextMenu::actionRenameThingHereTriggered() if (!variablePresentInRizin()) { // Show can't rename this variable dialog QMessageBox::critical( - this, + parentForDialog(), tr("Rename local variable %1").arg(QString(annotationHere->variable.name)), tr("Can't rename this variable. " "Only local variables defined in disassembly can be renamed.")); return; } QString oldName(annotationHere->variable.name); - QString newName = QInputDialog::getText(this, tr("Rename %2").arg(oldName), + QString newName = QInputDialog::getText(parentForDialog(), tr("Rename %2").arg(oldName), tr("Enter name"), QLineEdit::Normal, oldName, &ok); if (ok && !newName.isEmpty()) { Core()->renameFunctionVariable(newName, oldName, decompiledFunctionAddress); @@ -465,13 +471,14 @@ void DecompilerContextMenu::actionEditFunctionVariablesTriggered() return; } else if (!variablePresentInRizin()) { QMessageBox::critical( - this, tr("Edit local variable %1").arg(QString(annotationHere->variable.name)), + parentForDialog(), + tr("Edit local variable %1").arg(QString(annotationHere->variable.name)), tr("Can't edit this variable. " "Only local variables defined in disassembly can be edited.")); return; } EditVariablesDialog dialog(decompiledFunctionAddress, QString(annotationHere->variable.name), - this); + parentForDialog()); dialog.exec(); } diff --git a/src/menus/DecompilerContextMenu.h b/src/menus/DecompilerContextMenu.h index 7a1d5def..c71a2d27 100644 --- a/src/menus/DecompilerContextMenu.h +++ b/src/menus/DecompilerContextMenu.h @@ -111,6 +111,12 @@ private: QAction actionSetPC; // Private Functions + + /** + * \return widget that should be used as parent for presenting dialogs + */ + QWidget *parentForDialog(); + /** * @brief Sets the shortcut context in all the actions contained * in the specified QMenu to Qt::WidgetWithChildrenShortcut. From ad82407c2c1bc82b89a55606b9894def879626d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 7 Jan 2023 20:05:14 +0100 Subject: [PATCH 177/240] Fix changing the CC of a function (#3067) The QByteArray must be kept alive as long as its contens are used. Also in this function, Core()->renameFunction() is not used to avoid sending multiple signals for a single edit action. --- src/menus/DisassemblyContextMenu.cpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 50277c7d..f8604e6b 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -1023,18 +1023,15 @@ void DisassemblyContextMenu::on_actionEditFunction_triggered() if (dialog.exec()) { QString new_name = dialog.getNameText(); - Core()->renameFunction(fcn->addr, new_name); + rz_core_analysis_function_rename(core, fcn->addr, new_name.toStdString().c_str()); QString new_start_addr = dialog.getStartAddrText(); fcn->addr = Core()->math(new_start_addr); QString new_stack_size = dialog.getStackSizeText(); fcn->stack = int(Core()->math(new_stack_size)); - const char *ccSelected = dialog.getCallConSelected().toUtf8().constData(); - if (RZ_STR_ISEMPTY(ccSelected)) { - return; - } - if (rz_analysis_cc_exist(core->analysis, ccSelected)) { - fcn->cc = rz_str_constpool_get(&core->analysis->constpool, ccSelected); + QByteArray newCC = dialog.getCallConSelected().toUtf8(); + if (!newCC.isEmpty() && rz_analysis_cc_exist(core->analysis, newCC.constData())) { + fcn->cc = rz_str_constpool_get(&core->analysis->constpool, newCC.constData()); } emit Core()->functionsChanged(); From 3d49c4b65a952196e0df0f1e1ced9079b7523e38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sat, 7 Jan 2023 20:05:41 +0100 Subject: [PATCH 178/240] Fix parsing of new types from C (#3068) In the TypesWidget, right-click+Load New Types was opening the dialog for editing an existing type instead of creating a new one. This would either result in an error (for atomic types) or the old type being deleted on success. --- src/dialogs/TypesInteractionDialog.cpp | 16 +++++++++++++--- src/widgets/TypesWidget.cpp | 1 - 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/dialogs/TypesInteractionDialog.cpp b/src/dialogs/TypesInteractionDialog.cpp index eb2c2284..be363a30 100644 --- a/src/dialogs/TypesInteractionDialog.cpp +++ b/src/dialogs/TypesInteractionDialog.cpp @@ -22,7 +22,6 @@ TypesInteractionDialog::TypesInteractionDialog(QWidget *parent, bool readOnly) syntaxHighLighter = Config()->createSyntaxHighlighter(ui->plainTextEdit->document()); ui->buttonBox->button(QDialogButtonBox::Ok)->setEnabled(false); ui->plainTextEdit->setReadOnly(readOnly); - this->typeName = ""; } TypesInteractionDialog::~TypesInteractionDialog() {} @@ -64,10 +63,21 @@ void TypesInteractionDialog::done(int r) { if (r == QDialog::Accepted) { RzCoreLocked core(Core()); - bool edited = rz_type_db_edit_base_type( + bool success; + if (!typeName.isEmpty()) { + success = rz_type_db_edit_base_type( core->analysis->typedb, this->typeName.toUtf8().constData(), ui->plainTextEdit->toPlainText().toUtf8().constData()); - if (edited) { + } else { + char *error_msg = NULL; + success = rz_type_parse_string_stateless(core->analysis->typedb->parser, + ui->plainTextEdit->toPlainText().toUtf8().constData(), &error_msg) == 0; + if (error_msg) { + RZ_LOG_ERROR("%s\n", error_msg); + rz_mem_free(error_msg); + } + } + if (success) { emit newTypesLoaded(); QDialog::done(r); return; diff --git a/src/widgets/TypesWidget.cpp b/src/widgets/TypesWidget.cpp index ebdeace1..3891314e 100644 --- a/src/widgets/TypesWidget.cpp +++ b/src/widgets/TypesWidget.cpp @@ -293,7 +293,6 @@ void TypesWidget::on_actionLoad_New_Types_triggered() TypesInteractionDialog dialog(this); connect(&dialog, &TypesInteractionDialog::newTypesLoaded, this, &TypesWidget::refreshTypes); dialog.setWindowTitle(tr("Load New Types")); - dialog.setTypeName(t.type); dialog.exec(); } From 34018519defc3a7eae46473d7e20dff96b612c1d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sun, 8 Jan 2023 12:04:36 +0100 Subject: [PATCH 179/240] Cleanup and fix macOS CI (#3070) 2to3 has some suffix now and workarounds are no longer necessary. --- .github/workflows/ci.yml | 5 +---- scripts/Brewfile | 4 +++- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 36ff9aa6..86a9ce1d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,11 +86,8 @@ jobs: if: contains(matrix.os, 'macos') run: | cd scripts - rm '/usr/local/bin/2to3' # symlink to some kind of existing python2.7 installation conflicts with brew python3 which gets installed as indirect dependency - brew update --preinstall # temporary workaround for https://github.com/Homebrew/homebrew-bundle/issues/751 + rm /usr/local/bin/2to3* # symlink to some kind of existing python2.7 installation conflicts with brew python3 which gets installed as indirect dependency brew bundle - brew install coreutils - brew install pkg-config - name: py dependencies run: | python3 -m pip install -U pip==21.3.1 diff --git a/scripts/Brewfile b/scripts/Brewfile index dc80bdbc..fb6bc93c 100644 --- a/scripts/Brewfile +++ b/scripts/Brewfile @@ -3,4 +3,6 @@ brew "ccache" brew "openssl" brew "xz" brew "llvm" -brew "meson" \ No newline at end of file +brew "meson" +brew "coreutils" +brew "pkg-config" From a82d4402f8390b69d7e5e40eb65a282d36775cb7 Mon Sep 17 00:00:00 2001 From: karliss Date: Tue, 10 Jan 2023 03:45:47 +0200 Subject: [PATCH 180/240] Store action data as QString. (#3073) Fixes compilation error in newer QT versions, and also prevents risk of potential memory issues. --- src/menus/DisassemblyContextMenu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index f8604e6b..ab54328d 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -524,7 +524,7 @@ void DisassemblyContextMenu::aboutToShowSlot() continue; } structureOffsetMenu->addAction("[" + memBaseReg + " + " + ty->path + "]") - ->setData(ty->path); + ->setData(QString(ty->path)); } rz_list_free(typeoffs); } From 93acec9682e8e20c5e570b7ddc3ca2cf94ebcfb2 Mon Sep 17 00:00:00 2001 From: Tristan <35229978+TristanCrawford@users.noreply.github.com> Date: Wed, 11 Jan 2023 03:38:23 -0600 Subject: [PATCH 181/240] Add text debounce to QuickFilterView & ComboQuickFilterView (#3072) --- src/widgets/ComboQuickFilterView.cpp | 8 +++++++- src/widgets/ComboQuickFilterView.h | 2 ++ src/widgets/QuickFilterView.cpp | 8 +++++++- src/widgets/QuickFilterView.h | 2 ++ 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/widgets/ComboQuickFilterView.cpp b/src/widgets/ComboQuickFilterView.cpp index 0f9d827c..a7bcef60 100644 --- a/src/widgets/ComboQuickFilterView.cpp +++ b/src/widgets/ComboQuickFilterView.cpp @@ -6,8 +6,14 @@ ComboQuickFilterView::ComboQuickFilterView(QWidget *parent) { ui->setupUi(this); + debounceTimer = new QTimer(this); + debounceTimer->setSingleShot(true); + + connect(debounceTimer, &QTimer::timeout, this, + [this]() { emit filterTextChanged(ui->lineEdit->text()); }); + connect(ui->lineEdit, &QLineEdit::textChanged, this, - [this](const QString &text) { emit filterTextChanged(text); }); + [this](const QString &text) { debounceTimer->start(150); }); } ComboQuickFilterView::~ComboQuickFilterView() diff --git a/src/widgets/ComboQuickFilterView.h b/src/widgets/ComboQuickFilterView.h index ba913649..5dc217dc 100644 --- a/src/widgets/ComboQuickFilterView.h +++ b/src/widgets/ComboQuickFilterView.h @@ -5,6 +5,7 @@ #include #include +#include namespace Ui { class ComboQuickFilterView; @@ -32,6 +33,7 @@ signals: private: Ui::ComboQuickFilterView *ui; + QTimer *debounceTimer; }; #endif // COMBOQUICKFILTERVIEW_H diff --git a/src/widgets/QuickFilterView.cpp b/src/widgets/QuickFilterView.cpp index f6bb88a1..1f04c5b9 100644 --- a/src/widgets/QuickFilterView.cpp +++ b/src/widgets/QuickFilterView.cpp @@ -7,10 +7,16 @@ QuickFilterView::QuickFilterView(QWidget *parent, bool defaultOn) { ui->setupUi(this); + debounceTimer = new QTimer(this); + debounceTimer->setSingleShot(true); + connect(ui->closeFilterButton, &QAbstractButton::clicked, this, &QuickFilterView::closeFilter); + connect(debounceTimer, &QTimer::timeout, this, + [this]() { emit filterTextChanged(ui->filterLineEdit->text()); }); + connect(ui->filterLineEdit, &QLineEdit::textChanged, this, - [this](const QString &text) { emit filterTextChanged(text); }); + [this](const QString &text) { debounceTimer->start(150); }); if (!defaultOn) { closeFilter(); diff --git a/src/widgets/QuickFilterView.h b/src/widgets/QuickFilterView.h index 7c92c3a3..b6cbb15b 100644 --- a/src/widgets/QuickFilterView.h +++ b/src/widgets/QuickFilterView.h @@ -7,6 +7,7 @@ #include #include +#include namespace Ui { class QuickFilterView; @@ -31,6 +32,7 @@ signals: private: std::unique_ptr ui; + QTimer *debounceTimer; }; #endif // QUICKFILTERVIEW_H From 54cd0f1a428d9b55426eecb519b9c1610235dc68 Mon Sep 17 00:00:00 2001 From: Semnodime Date: Wed, 11 Jan 2023 10:39:43 +0100 Subject: [PATCH 182/240] Fix `fo`/`fortune` command in python sample (#3076, Fix #3075) --- src/plugins/sample-python/sample_python.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/plugins/sample-python/sample_python.py b/src/plugins/sample-python/sample_python.py index 6267b900..3be1ad76 100644 --- a/src/plugins/sample-python/sample_python.py +++ b/src/plugins/sample-python/sample_python.py @@ -36,7 +36,7 @@ class FortuneWidget(cutter.CutterDockWidget): self.show() def generate_fortune(self): - fortune = cutter.cmd("fo").replace("\n", "") + fortune = cutter.cmd("fortune").replace("\n", "") res = cutter.core().cmdRaw(f"?E {fortune}") self.text.setText(res) @@ -44,7 +44,7 @@ class FortuneWidget(cutter.CutterDockWidget): class CutterSamplePlugin(cutter.CutterPlugin): name = "Sample Plugin" description = "A sample plugin written in python." - version = "1.1" + version = "1.2" author = "Cutter developers" # Override CutterPlugin methods From c5f6cc0c3f1a3cb33ae7e53d2708ed7baf5e2703 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Wed, 11 Jan 2023 12:10:39 +0100 Subject: [PATCH 183/240] Update gha get-release action to fix it on new macOS --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 86a9ce1d..04c93efa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -281,7 +281,7 @@ jobs: - name: Get release if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') id: get_release - uses: karliss/get-release@23b8b7144dd5b0c9d6942b2fb78bd9ae71546d03 + uses: rizinorg/gha-get-release@c8074dd5d13ddd0a194d8c9205a1466973c7dc0d env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Upload release assets From 4e0e0000e15d173608b61f5df2ed055f9f6c8650 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Mon, 9 Jan 2023 18:19:48 +0100 Subject: [PATCH 184/240] Remove Breakpad Crash Reporting Crash dumps generated with breakpad were not made use of to an extent that would justify the extra maintenance overhead that it comes with. As Windows builds have recently been broken by it, now is a good time to retire it. --- .appveyor.yml | 2 - .github/workflows/ci.yml | 8 - .woodpecker/macos-arm64.yml | 3 - CMakeLists.txt | 2 - cmake/FindBreakpad.cmake | 65 - dist/CMakeLists.txt | 4 - dist/MacOSSetupBundle.cmake.in | 8 - docs/source/building.rst | 26 +- .../code/crash-handling-system.rst | 32 - docs/source/images/crash-dialog.png | Bin 29528 -> 0 bytes docs/source/images/success-dump-dialog.png | Bin 14629 -> 0 bytes scripts/breakpad_client.gyp | 34 - scripts/breakpad_extract_symbols_appimage.py | 55 - scripts/breakpad_macos.patch | 1377 ----------------- scripts/prepare_breakpad.bat | 33 - scripts/prepare_breakpad_linux.sh | 11 - scripts/prepare_breakpad_macos.sh | 24 - src/CMakeLists.txt | 18 - src/CutterApplication.cpp | 1 - src/Main.cpp | 12 - src/common/CrashHandler.cpp | 163 -- src/common/CrashHandler.h | 16 - 22 files changed, 1 insertion(+), 1893 deletions(-) delete mode 100644 cmake/FindBreakpad.cmake delete mode 100644 docs/source/contributing/code/crash-handling-system.rst delete mode 100644 docs/source/images/crash-dialog.png delete mode 100644 docs/source/images/success-dump-dialog.png delete mode 100644 scripts/breakpad_client.gyp delete mode 100644 scripts/breakpad_extract_symbols_appimage.py delete mode 100644 scripts/breakpad_macos.patch delete mode 100644 scripts/prepare_breakpad.bat delete mode 100755 scripts/prepare_breakpad_linux.sh delete mode 100755 scripts/prepare_breakpad_macos.sh delete mode 100644 src/common/CrashHandler.cpp delete mode 100644 src/common/CrashHandler.h diff --git a/.appveyor.yml b/.appveyor.yml index dc3f82d3..375d116e 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -30,7 +30,6 @@ install: before_build: - cmd: git submodule update --init --recursive - - scripts\prepare_breakpad.bat # Build config build_script: @@ -48,7 +47,6 @@ build_script: -DCUTTER_PACKAGE_RZ_GHIDRA=ON -DCUTTER_PACKAGE_JSDEC=ON -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON - -DCUTTER_ENABLE_CRASH_REPORTS=ON -DCMAKE_PREFIX_PATH=%CUTTER_DEPS%\\pyside -DCPACK_PACKAGE_FILE_NAME=%PACKAGE_NAME% -G Ninja diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 04c93efa..38f9b70f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -120,8 +120,6 @@ jobs: export CXX="${{matrix.cxx-override}}" fi - source scripts/prepare_breakpad_linux.sh - export PKG_CONFIG_PATH="$CUSTOM_BREAKPAD_PREFIX/lib/pkgconfig:${PKG_CONFIG_PATH:-}" # mkdir build cd build cmake --version @@ -136,7 +134,6 @@ jobs: -DPYTHON_EXECUTABLE="$CUTTER_DEPS_PYTHON_PREFIX/bin/python3" \ -DCUTTER_ENABLE_PYTHON_BINDINGS=ON \ -DCUTTER_ENABLE_GRAPHVIZ=OFF \ - -DCUTTER_ENABLE_CRASH_REPORTS=ON \ -DCUTTER_USE_BUNDLED_RIZIN=ON \ -DCUTTER_APPIMAGE_BUILD=ON \ -DCUTTER_ENABLE_PACKAGING=ON \ @@ -191,7 +188,6 @@ jobs: source cutter-deps/env.sh set -euo pipefail export PATH=/usr/local/opt/llvm/bin:$PATH - source scripts/prepare_breakpad_macos.sh mkdir build cd build PACKAGE_NAME=Cutter-${PACKAGE_ID}-macOS-x86_64 @@ -202,7 +198,6 @@ jobs: -DPYTHON_EXECUTABLE="$CUTTER_DEPS_PYTHON_PREFIX/bin/python3" \ -DCUTTER_ENABLE_PYTHON=ON \ -DCUTTER_ENABLE_PYTHON_BINDINGS=ON \ - -DCUTTER_ENABLE_CRASH_REPORTS=ON \ -DCUTTER_USE_BUNDLED_RIZIN=ON \ -DCUTTER_ENABLE_PACKAGING=ON \ -DCUTTER_ENABLE_SIGDB=ON \ @@ -213,7 +208,6 @@ jobs: -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \ -DCUTTER_PACKAGE_RZ_LIBYARA=ON \ -DCPACK_PACKAGE_FILE_NAME="$PACKAGE_NAME" \ - -DCMAKE_FRAMEWORK_PATH="$BREAKPAD_FRAMEWORK_DIR" \ -DCPACK_BUNDLE_APPLE_CERT_APP="-" \ .. && \ make -j4; @@ -237,7 +231,6 @@ jobs: set CUTTER_DEPS=%CD%\cutter-deps set PATH=%CD%\cutter-deps\qt\bin;%PATH% call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 - call scripts\prepare_breakpad.bat cd mkdir build cd build @@ -255,7 +248,6 @@ jobs: -DCUTTER_PACKAGE_RZ_LIBYARA=ON ^ -DCUTTER_PACKAGE_JSDEC=ON ^ -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON ^ - -DCUTTER_ENABLE_CRASH_REPORTS=ON ^ -DCMAKE_PREFIX_PATH="%CUTTER_DEPS%\pyside" ^ -DCPACK_PACKAGE_FILE_NAME=%PACKAGE_NAME% ^ -G Ninja ^ diff --git a/.woodpecker/macos-arm64.yml b/.woodpecker/macos-arm64.yml index 96ce1457..bbff7e68 100644 --- a/.woodpecker/macos-arm64.yml +++ b/.woodpecker/macos-arm64.yml @@ -12,7 +12,6 @@ pipeline: - export PACKAGE_ID=${CI_COMMIT_TAG=git-`date "+%Y-%m-%d"`-${CI_COMMIT_SHA}} - export PACKAGE_NAME=Cutter-$${PACKAGE_ID}-macOS-arm64 - source cutter-deps/env.sh - - source scripts/prepare_breakpad_macos.sh - cmake -Bbuild -GNinja -DCMAKE_BUILD_TYPE=Release -DPYTHON_LIBRARY="$$CUTTER_DEPS_PYTHON_PREFIX/lib/libpython3.9.dylib" @@ -20,7 +19,6 @@ pipeline: -DPYTHON_EXECUTABLE="$$CUTTER_DEPS_PYTHON_PREFIX/bin/python3" -DCUTTER_ENABLE_PYTHON=ON -DCUTTER_ENABLE_PYTHON_BINDINGS=ON - -DCUTTER_ENABLE_CRASH_REPORTS=ON -DCUTTER_USE_BUNDLED_RIZIN=ON -DCUTTER_ENABLE_PACKAGING=ON -DCUTTER_ENABLE_SIGDB=ON @@ -31,7 +29,6 @@ pipeline: -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON -DCUTTER_PACKAGE_RZ_LIBYARA=ON -DCPACK_PACKAGE_FILE_NAME="$$PACKAGE_NAME" - -DCMAKE_FRAMEWORK_PATH="$$BREAKPAD_FRAMEWORK_DIR" -DCPACK_BUNDLE_APPLE_CERT_APP="-" - ninja -C build package: diff --git a/CMakeLists.txt b/CMakeLists.txt index 3c615e56..a62b602a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,6 @@ option(CUTTER_USE_ADDITIONAL_RIZIN_PATHS "Search rizin in additional paths which Disable this option if you are linking against rizin pacakged as proper system library or in a custom path and additional are paths causing problems." ON) option(CUTTER_ENABLE_PYTHON "Enable Python integration. Requires Python >= ${CUTTER_PYTHON_MIN}." OFF) option(CUTTER_ENABLE_PYTHON_BINDINGS "Enable generating Python bindings with Shiboken2. Unused if CUTTER_ENABLE_PYTHON=OFF." OFF) -option(CUTTER_ENABLE_CRASH_REPORTS "Enable crash report system. Unused if CUTTER_ENABLE_CRASH_REPORTS=OFF" OFF) option(CUTTER_APPIMAGE_BUILD "Enable Appimage specific changes. Doesn't cause building of Appimage itself." OFF) tri_option(CUTTER_ENABLE_KSYNTAXHIGHLIGHTING "Use KSyntaxHighlighting" AUTO) tri_option(CUTTER_ENABLE_GRAPHVIZ "Enable use of graphviz for graph layout" AUTO) @@ -136,7 +135,6 @@ if(CUTTER_USE_BUNDLED_RIZIN) endif() message(STATUS "- Python: ${CUTTER_ENABLE_PYTHON}") message(STATUS "- Python Bindings: ${CUTTER_ENABLE_PYTHON_BINDINGS}") -message(STATUS "- Crash Handling: ${CUTTER_ENABLE_CRASH_REPORTS}") message(STATUS "- KSyntaxHighlighting: ${KSYNTAXHIGHLIGHTING_STATUS}") message(STATUS "- Graphviz: ${CUTTER_ENABLE_GRAPHVIZ}") message(STATUS "- Downloads dependencies: ${CUTTER_ENABLE_DEPENDENCY_DOWNLOADS}") diff --git a/cmake/FindBreakpad.cmake b/cmake/FindBreakpad.cmake deleted file mode 100644 index 3cc01ee8..00000000 --- a/cmake/FindBreakpad.cmake +++ /dev/null @@ -1,65 +0,0 @@ -# - Find Breakpad -# -# Breakpad_FOUND - True if Breakpad has been found. -# Breakpad_INCLUDE_DIRS - Breakpad include directory -# Breakpad_LIBRARIES - List of libraries when using Breakpad. - -set(Breakpad_LIBRARIES_VARS "") -if(WIN32) - find_path(Breakpad_INCLUDE_DIRS - client/windows/handler/exception_handler.h - HINTS - "${CMAKE_CURRENT_SOURCE_DIR}/Breakpad/src/src") - - set(Breakpad_LIBRARY_NAMES - exception_handler - crash_generation_client - common - ) - - set(Breakpad_LIBRARIES "") - - foreach(libname ${Breakpad_LIBRARY_NAMES}) - find_library(Breakpad_LIBRARY_${libname} - ${libname} - HINTS - "${CMAKE_CURRENT_SOURCE_DIR}/Breakpad/src/src/client/windows/Release/lib" - REQUIRED) - - list(APPEND Breakpad_LIBRARIES ${Breakpad_LIBRARY_${libname}}) - list(APPEND Breakpad_LIBRARIES_VARS "Breakpad_LIBRARY_${libname}") - endforeach() - - set (Breakpad_LINK_LIBRARIES ${Breakpad_LIBRARIES}) - - set(Breakpad_LIBRARY_DIRS "") -elseif(APPLE) - find_library(Breakpad_LINK_LIBRARIES Breakpad REQUIRED) - set(Breakpad_LIBRARIES ${Breakpad_LINK_LIBRARIES}) - # Assumes Breakpad is packed as Framework - set(Breakpad_INCLUDE_DIRS "${Breakpad_LINK_LIBRARIES}/Headers") -else() - set(Breakpad_CMAKE_PREFIX_PATH_TEMP ${CMAKE_PREFIX_PATH}) - list(APPEND CMAKE_PREFIX_PATH "${CMAKE_CURRENT_SOURCE_DIR}/Breakpad/prefix") - - find_package(PkgConfig REQUIRED) - pkg_search_module(Breakpad REQUIRED breakpad-client) - - # reset CMAKE_PREFIX_PATH - set(CMAKE_PREFIX_PATH ${Breakpad_CMAKE_PREFIX_PATH_TEMP}) - mark_as_advanced(Breakpad_CMAKE_PREFIX_PATH_TEMP) -endif() - -# could be simplified in > cmake 3.11 using pkg_search_module IMPORTED_TARGET [GLOBAL] but this would still be required for windows -add_library(Breakpad::client INTERFACE IMPORTED) -set_target_properties(Breakpad::client PROPERTIES - INTERFACE_INCLUDE_DIRECTORIES "${Breakpad_INCLUDE_DIRS}") -set_target_properties(Breakpad::client PROPERTIES - INTERFACE_LINK_LIBRARIES "${Breakpad_LINK_LIBRARIES}") - - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Breakpad REQUIRED_VARS Breakpad_LIBRARIES Breakpad_INCLUDE_DIRS ${Breakpad_LIBRARIES_VARS}) - -mark_as_advanced(Breakpad_LIBRARIES_VARS) - diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index ee962d2e..956fbd18 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -77,10 +77,6 @@ if(APPLE) set(CPACK_DMG_VOLUME_NAME "Cutter") set(CPACK_BUNDLE_APPLE_ENTITLEMENTS "${CMAKE_CURRENT_SOURCE_DIR}/macos/Entitlements.plist") set(CPACK_APPLE_BUNDLE_ID "re.rizin.cutter") - if (CUTTER_ENABLE_CRASH_REPORTS) - list(APPEND CPACK_BUNDLE_APPLE_CODESIGN_FILES "/Contents/Frameworks/Breakpad.framework/Versions/Current/Resources/breakpadUtilities.dylib") - endif() - find_program(MACDEPLOYQT_PATH macdeployqt HINTS "${Qt5_DIR}/../../../bin") if(NOT MACDEPLOYQT_PATH) diff --git a/dist/MacOSSetupBundle.cmake.in b/dist/MacOSSetupBundle.cmake.in index ff8bdb35..0259ac41 100644 --- a/dist/MacOSSetupBundle.cmake.in +++ b/dist/MacOSSetupBundle.cmake.in @@ -3,8 +3,6 @@ include(BundleUtilities) set(MACDEPLOYQT_PATH "@MACDEPLOYQT_PATH@") set(INFO_PLIST_PATH "@CPACK_BUNDLE_PLIST@") set(ADJUST_RIZIN_LIBS "@ADJUST_RIZIN_LIBS@") -set(CUTTER_ENABLE_CRASH_REPORTS "@CUTTER_ENABLE_CRASH_REPORTS@") -set(Breakpad_LINK_LIBRARIES "@Breakpad_LINK_LIBRARIES@") set(CUTTER_PACKAGE_DEPENDENCIES "@CUTTER_PACKAGE_DEPENDENCIES@") set(CUTTER_ENABLE_PYTHON "@CUTTER_ENABLE_PYTHON@") @@ -82,9 +80,3 @@ foreach(_lib ${ADJUST_RIZIN_LIBS}) get_filename_component(_name "${_lib}" NAME) file(REMOVE "${BUNDLE_PATH}/Contents/Frameworks/${_name}") endforeach() - -if (CUTTER_ENABLE_CRASH_REPORTS) - message("Copying Breakpad ${Breakpad_LINK_LIBRARIES}") - set(_breakpad_lib "Versions/A/Breakpad") - copy_resolved_framework_into_bundle("${Breakpad_LINK_LIBRARIES}/${_breakpad_lib}" "${FRAMEWORK_DIR}/Breakpad.framework/${_breakpad_lib}") -endif() diff --git a/docs/source/building.rst b/docs/source/building.rst index 5f2d9c0a..95e9cf74 100644 --- a/docs/source/building.rst +++ b/docs/source/building.rst @@ -113,8 +113,7 @@ If you want to use Cutter with another version of Rizin you can set ``-DCUTTER_U .. note:: If you are interested in building Cutter with support for Python plugins, - Syntax Highlighting, Crash Reporting and more, - please look at the full list of `CMake Building Options`_. + Syntax Highlighting and more, please look at the full list of `CMake Building Options`_. After the build process is complete, you should have the ``Cutter`` executable in the **build** dir. @@ -252,7 +251,6 @@ Note that there are some major building options available: Cutter binary release options, not needed for most users and might not work easily outside CI environment: -* ``CUTTER_ENABLE_CRASH_REPORTS`` is used to compile Cutter with crash handling system enabled (Breakpad). * ``CUTTER_ENABLE_DEPENDENCY_DOWNLOADS`` Enable downloading of dependencies. Setting to OFF doesn't affect any downloads done by Rizin build. This option is used for preparing Cutter binary release packges. Turned off by default. * ``CUTTER_PACKAGE_DEPENDENCIES`` During install step include the third party dependencies. This option is used for preparing Cutter binary release packges. @@ -271,28 +269,6 @@ Or if one wants to explicitly disable an option: cmake -B build -DCUTTER_ENABLE_PYTHON=OFF --------------- - -Compiling Cutter with Breakpad Support --------------------------------------- - -If you want to build Cutter with crash handling system, you will want to first prepare Breakpad. -For this, simply run one of the scripts (according to your OS) from root Cutter directory: - -.. code:: sh - - source scripts/prepare_breakpad_linux.sh # Linux - source scripts/prepare_breakpad_macos.sh # MacOS - scripts/prepare_breakpad.bat # Windows - -Then if you are building on Linux you want to change ``PKG_CONFIG_PATH`` environment variable -so it contains ``$CUSTOM_BREAKPAD_PREFIX/lib/pkgconfig``. For this simply run - -.. code:: sh - - export PKG_CONFIG_PATH="$CUSTOM_BREAKPAD_PREFIX/lib/pkgconfig:$PKG_CONFIG_PATH" - - -------------- Troubleshooting diff --git a/docs/source/contributing/code/crash-handling-system.rst b/docs/source/contributing/code/crash-handling-system.rst deleted file mode 100644 index 98004b14..00000000 --- a/docs/source/contributing/code/crash-handling-system.rst +++ /dev/null @@ -1,32 +0,0 @@ -Crash Handling System -===================== - -Cutter uses `Breakpad `__ as a backend -for crash handling. - -Crash Handling System is disabled by default to not interfere with developers while debugging. -To enable this system, set the ``CUTTER_ENABLE_CRASH_REPORTS`` build option. - -Solution Description --------------------- - -There are only 2 source files: - -* ``CrashHandler.h`` -* ``CrashHandler.cpp`` - -And the API is very simple: One function, ``initCrashHandler()``, enables the Crash Handling System if -``CUTTER_ENABLE_CRASH_REPORTS`` is true, otherwise it does nothing. - -As soon as a signal is raised, ``crashHandler(int signum)`` is called with the signal's code as an argument. -This function first writes a crash dump to the operating system's temporary directory to catch core and -memory state as it was at the moment of the crash. - -Then the crash dialog is shown: - -.. image :: /images/crash-dialog.png - -If the user chooses to create a crash dump, the prepared dump is moved to the directory specified by the user. -And then the success dialog is shown: - -.. image :: /images/success-dump-dialog.png diff --git a/docs/source/images/crash-dialog.png b/docs/source/images/crash-dialog.png deleted file mode 100644 index a3e50eb26a75f75b0d771b6a2a47487c90107950..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29528 zcmd43Wmr{P*fxqNA|Rl2qjYykilj()hk$fV7l^G*iqjpeJa!d;79i@&Ea zWVpGf)@91OOoJ2E6+;r&HxtbVWf;o465~5bvbvcT;D5YQ#G(B%XB@Y1h2GI$@h(3d z=|kGq%BX;n%Nzy!*d>^ZD?*k->v|13~!B3*l=E_JSV}Z*F;rvgZM{Rq-U}3(pD^%N47Ne!IE3vtxvK8?$f=ruWH~2H4--ykCBQ}$H6hD+|?R22r1XpR& z-r)LdNwIL}nzpgak-k>@=YY{EdJG+3&?~0@xvwZm3dtNrBYXc&b@T0&?OkWOEAej_ zvEc59Q>=Oe<&JxB+7rQZ}J;lxBsP!G8&yV zeH#t)yMRn&*zUjSbPP&M`_@AHs`|wu(zpa(u67~J>9zLZM9SjWbI_F{_ z4MlU+^=(Xl$-yEBooB(TE2MANZ^)V&Mgd=>LnwCCG+R_HL{?3@pxt-W^#1IbhJCb@ zmSuE}WX@HM%u4D@ycQ|KfJUCtc3JhDPZy536;f9{yu6|{k&`9QW2zx+8TR7T9 z@=+Ss^F-s*;)`u*z4unzD3!*$f_u0<-}K+9v`LUFP(JMo9GE`+_4vA&Ax~InoeX0?e3GP0Ii+}Y{Q-TxYaX0`K$>flp-E=k^2@(CNd+JGRAYABZ zqdU}cUfafpG;(0$-eiM~h-km0CFx}B%<=GFIa48{^50B1IGdp~m)4^9uY4>LcKTeo zFZIDqW#{FwJ8VjOKU_@F`Jpf~Gs8cB-q+v%b)mtDhmVil=h3r?&?6$jyF_cDv%| z&qy!rQ1TY5QO*CT;5^K-t`Gus-dSb0*ppB|-236&V>hUdTs~mX;Q-uAyOde?LT& z>^&bJVTx=|04m}3L{VIQlQfkGStN_aB!jM-G1^Tc5mCzS7Fo+8e8>uutST|@M1bOB zRH^v;$m6Cs#DfEs&7-fu!8da5IPOtF{w<5wv-6;TU?7oer`(W{7qt{>k!Oucj_1ml zD(^_m$ZJZ8ie|rJ+nxEfBJ$VtRHM;*jnQX2m4t-B?M`OWvoXxDM^4?d_SDaX$LW?~ zuXSlq1U=;2_Oh_?&cNcccWk@?OW`D2JJcj1R8g!4dUDUx$7AA?k`E3JT(`foI$AEF z#Ypv4M=RGHOb>N^i5oggU^#r|>6KXFKIFpB>xR)T{JpbNM}NXZPeo&ER(8BKfmEyJ zU^xS^`!87=X^HAU&H$3-Y(?mPGLeIBfpUMu@%QunQB-sn?%--ojHuGnCAn4(bR9x2 zisaOV#?{SDaRY<*kqV=hbLC0*Kj6rN^gl$+NA|iS(b%cH=Te@Kv za^smU6jH8{5<$Y{FdZ8(hEu}z$0rX=t7o;C3{873L-4qM=E^kD($Q_M@34b4B5c;R zDd#7B+)|o-S)Jig%apH7_ZymX{E%CMWl=5dy8UeSMa?H07Tc3mV=l|tPr9kO-4}Oi zlyL({q#V9pcj#YP@D43>Ld41Ix!KIdsUk=O+>dvQpoxAc9v&XwhLij96|(-CaxiGs zyarFw;Bpie8hX)nlKnYKz1f}f1WB#j#kMr=eep!IPxC!z@umOoiN6Hj)I?*4pw2_zQvoV-(W>h%QNlo!L%R{Y2>q=m+ zWvTPKU*PDjBMlbv=1{_COdA_6tA*~!rSO%FjXrQnsHm92=I8n0W?$B3h@EXZqV7rO zY7Q+vAO;16lJoKP6t>i|51}21Y)`ikON6KCFFlH6XY1zKr0G^!zSVy#EpYa4?KQ#Q z@HL<0uS<`9+ATzK1_p2A)-VT`u8!sc{Q|>}2Nu03behGFQWti{ix7LBc!C~B{I}f59h0NH%p->MI6DP?hT5Nqcz~9-sRQpJe{7%M_vC@s2TX z{{;T+oJ;EHAPXZB&^>6`*k2b_S2sZ;xee93B7LWn()G*0&(6{I9T{CiKih^AnmOjL z8ubA=FdX*l&#rH7SUk7&S20T?Vw|$NA98JuQl-6iSyxw?DlD!@G7Z0)jn1c)XNkWd zbZP%8WHyue!OG8X+UNMq9U2i8yV6kl_lH-O3;j)L(NpwXhww;h7|*sxo9Rbny?&p) zjl3`O!c~Ln7+(Lig};CJ;C34#R==FiWqQhaU$=#uX}G#gG#h!S^JjZD2NO)W>zk>E z?Cfl|bRW_tegPh@P3`Kv3uvjx-DQ>K3{e!)*!cL7g^uGaSw-d8%~We@yAj(-A9Y&1 zUu&v>2b;^G_76Y5dixDzKIeV??hyPJFJCH7B>h#P!{)Z0UvB&UoQH>(TepP#T^ z2ddNTUGznL{TRJsgbhSL9<8mR;%W-x`_|4y<&WBSH< z(kc8+N0l;WOxjH3hpHN>O6hNDsvc7g`Nh_MMr?0Mef(n?leDUh?o}jnFxKt&=Hz1V zU%Q8Nw@N4#7Jbo(O4BSUtu({I!cx57QZdohB|$*oKGHGgxPimM!H$fIvXDJmsN|Dr zYSy@2v&N0zQ&*=;N3dZ*VL_DK-000MFS5%2eQkyhAr|D=hYN}l?A&6sU6!1eA(lvfej(3eoZ&L;HUBysCCN+Rr)yMFWh?ua)z8Y!1OpY=q)Fr0$OwDf)>LE_ z4BPdNA4o*ZXq8A(KMuqW4KYe#f6h_t7UGHBj#r=bYMs%RrHVSajt)FIyLf-28T`S= z+M20o%G2brSeedkbyQ-y@hIKxDX7u*ZCb9(<790Y5iv0m5)%A73W{IXKVLu|4t420 ze#NFfKHODWFYr2~p#Y>wC7Ub>!C|CfV){0e$mzKIFX(Wg(U2|S7r>(A)%X+kjpHF1!Ebh8cCa7@FpoUy2A$P{FBvqai(*(OH6^G5$R)whaC zBt_*7s}rwVRFWidnf(A&2R2$gdT3~fobtlGB(|K*NtLU_;;nwCPLt7z26PIOnD|Sc z{9agR%oU*?De3;fL2*sOsOkFt&8vW)=%P$HMXy;BxlX$K z`Xbr47^Y-y4ste!o-@FQ^bbVkFg1F4otzp&9Gxan_xJZB28?|M=6V+z{ohB$aGnns zu{F4$8Xi5~aqs5-({JnQ!Uwywy1F{JqtoDMaJt^tYs3~tBG5lmX>zk)IU--6Y`N5u zf`EdO;zpkN_%XIln%mjz51MN^{8zoRysqczAi2cXvCso*w?% zH((&;N{xogswp0L-SDO4>Ov*73J{?D;p-zfB8YbtMG>c}@%{ZaM`nd}$m6CQ9G9ns z<--%9)=7FK1X!Q#CsPTL=8Sb`J~vRg z3r%rL!d90Pi3%4bYj0mnoo}j`qj)Jo%c~Q#agQ?4uiDhC6`7Uw94=hWExw0JuHtra zakxTzV}o`{2?Y{N7gJp4^VkgkT1ZGQk<039-v5IF zvQ|o^mt}b8?AdBYpOZ5|nlC+Zo*pNavxzyFLdU>Bp;S^@QMs8?Q#wD)Vd3zlXnW*& zQ&d)#SkH((f{*j6qrH9AF6Qd`x~QAD-le;OLm1XB0{=B_0H z?0g?Ig+zKsN8gsHs;zDRyholJG;ffVjhCi^q>C~!qj=KQyo_OXP*9i7X>}>Jcq&n<|rEhyN&aG$NU z7zk3z8`?obyX3H1l`%KhtRA-+r+VZ6sl5R;N%G4GOI~Bczr!{nqWPCKi}#j>h9Z)- zZ;*n5IAdi#H;0Kw$!+}&BYIlP{-8q_Ge%qW9Be5KZMkK+DdBuTCAPJTqbVtTTTExR z`BtQ!ye||QF6I;GQ|SEuy~@i>d7R>E6r`2;n==(}y)+~H4{mM*90aJs!os5B;-~%e z&}f8SANSKf>X{}t_9Sp}ZqIj`E@v$q59bpIxvg0YI$rR)91eo9qdDa}9P%o;UvDl>ca$m13~S)#>e`%&-y;ep5PmcgywEniuR zUqC=oMrN(EV0_z=QoDg@#Mj%a&UJ@v2Ol3S(ohYShku}2&k z%HK1i(*8_A#+HcK6V^REoJt?`d3vVMlw^6N;fOoRT_E(2MA+%y>CtH#EWjRCcUL>6 zN6CR)WvJ&L^#xFkEb-SlT2oA-J)Nto`-6Ul5*c-3q(zC^jj^9VuY8S0`q8rk+i?~H zMgqNhtO3*LO4eX@0GNJ#Gd6VEd~@rIsIp_s!%MotA@_efQUL0*h#;bqaWjX5!L(1j zkIzLxq=VX;us1dEBm8d|aqq0p8$K;9_ltd5{XNx9-*Z)h`iA2pAAznDAz1};78XlW zp0F^q{Tnx%P~%W>@}wF|!(FBDll8Tz4^Fp4$o|RSAMVC_C;V+%s)@vlCw5(p##{mD z`26Kd&(u^PVo%8G*oNyWW}$94U=Nmy6`^^lu2}Wb-7{xzv2ZQy?CrBvAe)wt27&cT zjv~}ieewm-ojqzxYjQb?WKn&GH|2T-Rbr)O23Lm*Sh%=n%YNu%IbU!g5NhyWs`stg zWU0=;@yZ_natsFJS@B-KG-AUC3LOOn#fu=(js~Z_h(2tZ7?-IAtrT}8me*96k^Y(u zyy`Wg>x7}viPClbMuWHPb#TWu3dd5Ia_0>q{vOlAyrrRDu;BzJmKisVVIY>2+l94eb&8NAt$7`a8L+I|*LL80sztTV= zl`OBBUe$QB$7M+-AmG>H<<4r}X&YSK1&XQMs)q@(rN4h;%*@5b#n0i)At%V?KR>S> zMj|A9S{=>j-M{l)L;@zi{R#YOXlVEcozK}$fH8E>Y=^aC2RDa$ttGu!@D?L4e z{_|%nqRK-Lc@3+nHS{@`j0y9dxkg;Sm**lWPJRNd`&|R$e(7y(=6OCl_WXq0Pi^VX z9`M-Bd2VhH?(I&o^t>O0QawGTLND&@Mwo%pb-HdCu5V${bFnvdGg3IhSTj(P%;S`p zxk@Jfny|xRL>57sLi@APOmO(nAL#)xu^!v?ZC050A}EuTKC#PVw_DZqDy@)6$SxSD zJOOA(TPG5v!c0+-NqH+BU0<#qZqTn3&CF;4C020gzH1XVgGd?o++OV2+1VNN{iftF zH@b0F1~WZf*l)VUi?7k;C|4$l3s8Bi;G`^+4OqK#vz)6zjp;{Aaz|#_Jp)>H``U#Z@ETvyxaS|($+J}mbA`d5m!Q>uaNK@l(|mzrwqwpucsFSwuvdcc z{G$!qi9$nS9HGbjsFq5UBc*3@DGt;e7xsmPXf2~TtO-84o0HM27BBnb>MlQAEp2u9 zqY!*z?q!xP`)bvM@FWD!OxG~6FU|9PZ0({9{%&RgZ~ps-dD4|_&3 zTl&N{BhRmS0_AVvSB?apM7`dIVxqU&FdhCA_Bkal+c;Dqlkpu*K5CXk_%}eb0oYBH zh+W^V?>XAb2 z@t9*VaUA=gpWmbi3Hpq9dULSwLX6^K?N!w5M*{zIVLFx)vZClO(T1b9gP%O#Cq7GQ z{}o!oz8Gdr6H_xyV|8>R^8U!oS7BJ6Ei!##VH`IO3HFR4lrd5YGqY0zS_()1^tSM) z{xfkn@W|T!Gte@IgW&%2*naX-!@q{PKyP-F|HmE^&Ug6#(T9LJ@zJy{vDQ>}s#M3$ z#YLiM;y0*XQPCGcY8XhSByG>p1@$9^I4NUf2)Q+~>l+)#tF_eloB4r!B$_pvu38in z6t=QEQKWiyes*R!|I==Lef@Z7YDwK|sZfPpJQUyf(UL9kuX(l6w{IBO*j*c6;);eW z7&sN><=ZB*i-?50lRG*-X;xXb$Cn$LYvZ;)UGnA0rWCTK!B%;68UD44i%Y<3;!iz) z!vH*0(A1Q2cIJA!MLykP#n;u1pwEEFt!ZSDQf0NZc}jV*=lc^;Bmy3`$8Ex24Go9fI0;bGyl(OB>xqDc6o5(^ zkd#CyC+C%De8gyYQ?aqx)a-th=@EX|+0#>LIEUr{Cd!nJhrq5Q@7Va*=(>ea32mP^+|ItjWy*PEk=&{p=#q{A}mKT`DvO zE_&OV#4#WoPgY<59oPeKmz6v-&-WLr3G21P+V#sMk4Cc)>0*L2Gs%GHuszX;yEj!b zg&Pv^f3g4)&?&VKN88(`XInyHPr`E%HNY)f+u1Q=9RW8Bq2H+5GaF20C-m|0Id^Xs zOCPUL`I64yTR;T2z~tB7#`k5ZzR2v=mAJ6?vzx>u>RuotE%nUaJ9%9lxZtGi-KkT| z>!DJ$;c=M0K|@1pYCK=idWoy6tIMEQpUfdP5w>jk zVUw2K`)%M*x0aO}gb)ZI>*?tMRXdJJ=j*^GBLyYZGv!8YQii+qem4(ycQ*GyQ()7Y zu222~je%@fqRe~29aL!{LsV3hlIr9iOi(v$Y;1)y1S*6qws3GlPxqB7whE>8whHC* zxuHpTY(}qS61g%gYD+9<`p9VHu9x*GbtBqH)gB*9~ zk$@0{jDq}GO6u#{72#)DS@9gjlZh$4a)XDL-t!Mx_4B<7Wre#{OWIlgoO#w+n(hG~O6xrH!4V*q1+= zwLM?Yo~oM)0Cg#aw!y-zQ+94{;u)i6#V-ewk;sIEK5!wk`8w7_epH|P6GSa8oAOt$ z0Q2i#r;Reh{Pz;ripoY<0K*ikc!4cowZ7*8CaeNojFGW%`Oclp=A8M%-4(3WxpJR~ z7byRB76>J+d29okmQ7>n&CSgw{qYUT);O5$aFeBaDEif?^bU@W>rcA(LcEUKaBbBV zQ`6@UxpRxM8+U^qM=cWa@^8R->;QU1wdPPN>6I;*-jEw-AZG@43yFe~07lp9amF7k z9Gpq>2WO+<`*9dGM0Kr6z$P!(gp0*YoZmgOwYUEY znk!I7fl7^7QBlEjI``K3XjaC|%&cUSe7^oAroQ9;bYxW($M4_2ca7YI9+`t9FQT@@bufGu-Gw5MOqUUqLxiym3W5o8%c*x6U(C0a*TZ>kmFF;iH>p*06 zS=3(i-m}73#T*>JIzKmBY;ps9=6C~F?{`XyjM&|?d z>&Z_>YzbnEprM|gv&)^$*|e4)1X@i`Pro4{8UEpqqJDn~d>D*EozmT2Z2S3zg&6>K z!4tfA@#1)TEgZ}c^@oXFx&hJT@Q)>`Ybz`5d`B&RY$Uwbj@$oGP)&M1O}4i`0~HM? zo5rtW_-NnK(o$tQ1K+GWQl8Z#PZz__cJub-Ya)4LU%*uclj|LPE1s*cw|)aS8jY0K z(oP;KO&0mLR!kAl^q1uF_H9A@lxZH{r@_@76b%|+! zg7f53y1TmkSq;0Fm$!X+m8>GwsG`dCSKwiY&qwHn8JGxmYu&64m(t&c;*HTdkBkV_ zy7XE87COznRK!TI+9Qy zNH_LrD=?#g(_3S+6xJd-avikhcCvw+!0v%&elg^vk<@TFTaS_=i`eEP_=v8QmJl2l zhkL|8Yw^91R{n0P@@e&I$!BW~U5IH;7W2@W4=|6=pFdwrdN<+#ygssfATbu9Bzs)*~PuIGT5>DE*{rTfZ8!ppc zRE|q8n6D!gJtu&pqB?#g0oujp4{imZ7%x;{JLM+&`ofWTZVSW1!(ZEO1XicU*_seY z`>t$msup3YTY=e?M1BK!A_Vg@s7*MqYB=A8pPoIOoSYc6C!t76(x6Z=={EHS$I#>P zITwo|vdGEFc~9T^-N31&2(S3r+S#pKxIvR7WTI=;Uz4)VC(AL#v4duvEZ`6eT7E~e zHyG@TPs?5;38$|hOS+x|8-@KB|Mr@$4m~zUkWP@Qtmb0Vm($G$wjFt6nRNTBw({QM z;Yqr>@~o_^Xg4?p*-UzhoKCEp4>Z&@#6RgRV!*$_!|Mf`z<8P}=#;4E{fJOE<8HUR zP76BoHJ}j*=f@PYRc0cFN8Qqd~5i*=EFzE^D{log0YEX|S4Tn+djh!HTU8R+F%-ERXqRwrpm}ZuEsOxGUwXKs=^>iwz z(WaAb!gZs#oUZQ9u}otWUdMg?N3d*COga_+nnpw=Bn(X~deV=DYl{c2Pu51ws~Oxa zBI}PP64*@`PL&VS&V~|gT(6p4%qALQ#C#Q!8dNQF2Kt7D^)k6#SfHWfd9syuf5gvB zWLg3cP;lo@oaty7U>#}mft`sd45+}-m&CJ4&qGEHC9+0M)mtp<>nS()6Dpfp_q~XS zhzd)Jl<77i`@+GK`~Zt?nA#%EWVp+&baHhCo$y~gAc4>o?Od_bc)kInwdrJ*aPt=2 zbW~hiPvv+jB@a*CERJG^HAnK6zGPcx3hDmdC&|V)pc4$WBSaHBGV3;(ws7l>j(B*N z+9fh-*1Th9A2*l$CMx=~YYX^NE6dAmeNnL~vR?qm^V;S3{{8zz*mRu^m~yrJaL<6I zh|^sCixLuRyT8o}Mm9`=Z|^|hu$rx!wVz#0BDS*v5r8KbTgP`aG`*`(&@(>H1l6h? z>3*E~J3Y1JnS!h9+3rbb+~)gC^{j7T$Z+M}pCMU~i@;zGeNLVROWNJ__e5V2KOT}b zp(RN|)&7GqU<6G8oK6;q=tS8Lal?bj0#TO-b838=xygBX)BxhB3jY$%VqJnSVpvVy z@cx~ui(^_3(0R;4G1pujSHIl9OSDUzoxZ-lO-$#m29;v90aeDn!NDqIN&2HZ6>y=! z8;32MB10E9l!)esgQ*K^6%y2_NL`$=`5otA9#Vt1_q!MF6*fj%rAx7lAAAm*R7i6Y zC!tU%Gc2)&=}~_=*QP?ew<{vknzp>G&&JMP@*_n^_WoHkG1UKdLSK``zQW=7^t=J; zWNYu3sgNb^*?6f1aSRguF=|>RIlkjq-OzdfYzS-Cf_!@+OuoB{$LERsdv6heA|gqF z0qTOGl+5A}K-mU=0^a`Rhm(+y0Pu`1rm#OON(Gi?1GN>pWV1fu1|7@(j2VDN+CQb| zrDOaEx{8#PR9Sg>hS&hkrpHwrlkV5PRZ2M6d3yhz8y#(-!G%2yi-6nO5{igQ$fsxjT=;+R0Z^`2YOt@glo9PxmKg7aAL;1x9rHRJ~y@>G2s7jRval?9{=rl(< zl8_^3!Z?68jIMvJyg)!)+1(BPRQjERQDx$Zg01pL1#A1~DV-#mR961$L0HBRyRc1;MG~;SY zAdTJzD#)vU6c-ntNZ~vxv!i6@4*&KzR6It!&j{7*_bB80z^Ad{1Y`#zHU)L%#$m0E zrsifh4+V{-$m*pMN_KWkfZ6Np*0yI$_N-*~xj?WD@`ORx4EBfHU;=?OR}L zvD*KW3?t#PaZ2uo(S89w`|wXvixoD+};x-)?YG#pxtw z%vgn*N0M_ke84GT<8aiJ1AV51hPig% zXnEbVIkd>aiX|~bB{#09$ciDVFTT}Q5U7^L56+C>q?kHs&Q@FWRBh#IY(R%fasZj( z=NAADVQql2s-|YJY~G)~K6il_4}ka2cNZY2d)#lZvBeY&-U6VoK_92J(VR4=U#&7V zSCGrQcj12S?iE8llNjdbk6_#rd9gQ%iH&W1;U)7-U#DT>h*~cy9GV7I!Ou|)lFBKJ ziVWx|;f&X!04H7)I(0T!IWliQt>lK79(;BCOtaS7$_YVfv9nZ}j&b}#B~L;^Z0+z+ zwjd)q+JZLLhnCi*N;@bh$kp8)b`&7z{lw+JqoVo-1}b@{fu-Bg5b&0i)P@9EbHQF^ zk}I1L_S71c0d>=-$^m z^f{n`gQgeFz1b>!cX=>G&L1t6BL=s8a3G_f^bzEF8l4Zxn7D@TaS1U8P7IA}S^Muy zmBq*+!PJyI5^R1ZDP7pYJi;vW^vT|yt)`}i|Kgugt#;TPNO=6IeY(S`*0dto)Y1?a ze<>y==J@)+G}79{BoGR{_+G_z=t!tGS!ZVm3T>v^5EqCeWFSD$G~c9^x^D41BElCS zA21wnc7S2Z8Qbi5f{~H(sa#=J`NqpMPkuOA@DI3d2N?hBo12MOptC~9hC4wrmDOFzXDamVKF&)%j3eB(~T1mT*!y>nF0d~89~wPKvqHJ!8cIu3AOH;9yJ1hjY5wz5hW=h` z2|yYk(AT!y?g#5%2kr!df`a@P=Sr%7V*8I4LV<4M<#F{sQmW2#hfPC610-Ns9Jl5F zC77=xe_$PDCE|CD@P4>Encah)jLQi{CME`hc)?<5Gc656e$CFE>gB;g&#y@G_zxCT zz#9Y76j*vwCu|!I0*zW{;t_!-qLIftjYpnGL}dRT?IMV4o15Q8PbwQW3K=+aiYfEI z#4+6$KjMQ_8xS1SxU_464Kg=?T`iT?;uU}1OHp(LD9ZHNI7uRhS;x;H%)zUlJ%T(q zxN5kU_f>&KYS7b-Exl7vyMHsqP|i%l3!@Ry6e1N=ob&k{kKX_SGFqy`2l&Czj%O|6ep<)aF?U*?zZPcmw`IkYD= z-E1b^-|j)NuyIDG8(9H@l$X`jx(F?tZ+e16A@gfZnM;gt^mH^ zS02FWKjlprx8Pi8x;30K=xxl!{%u(QXt7x`;%}B3`nl+#}z8stZ(?tDzk_;voiUgpwPfTE!sD3e*qHAO7%d?>XUR-=CDwO8UUt&;}%XVAP$Rj-O*lRN<}tCaA2=g#@Sj=s?#MMGNi>RJBXtg^BQ zu$7pToP*lkJw1UyXW73oLx+w{O#%GfovBt*paVbeFOBGjs$aMZ;N# z|8ac{0MV)2nP=D=>+39_eF9D7@7@JK|7R0%dUmVfyU$~F_*~vcO5*X@zWWn^E&|qn zJX~nB+)yGprQ}Zk-@0tAoiSka=xW}*K$AK-p(a&QRQv=KjxV^(8_mW?6a3%lfSg>m zeIN!~NS~*>rD%dLK_MYVqgs%{rWgeUPfyPo8@qcE{>y7a&~5+}(`c=+6dj7w^X!X~ z6X;vbfkaAWQ&3Tz9@H+K0z$r^phJIm5vO-@abbKOKMII^nb}%yBe0*$`Bbm~2#4Ja znBVcN4ln%?{9(=rv*6Q@8R%e(@yt^AeHb{e|F#wQ&!8p|eMX?8Vi00_XnDDSMtOsH zZOB3J!K>jmW0&*6``ldsg3I{r{^v;usSpXZ2{l0FK!-t}tF>ySu5EeTDcq}J%3-)> zd8$S`bo?_Z>ll1f1jN$$>JH}<|ENJkHMNX z=6%rCdv_4)pU-*e1j&AHZ)>~U6{owt-WLUs{yC-b6@f$;LEnl0Ny@LFI-$WN`ys&ooR~QqwN)A4-47BZ~T-;O33*$QMn7;C+AxLK>JApgY{3 zkIPxkH5_=W$<_7zhElP6cG|jM?SwWr3jhOF`*U4~$5E5Z+>z(o7sB~+ndkxkz06ci zcKbhXzS!#hf3{CD7H8(>&PII%0dkp7t}*Q+gIp2ALN3k^n(&E;^CzCWUkPB&&BB{! z0rE$Vyu>?ZJEo@=PXs2wo>@7P;qOz*cL68eCAP%@_Uglrck?1ZSB>X4W@FT>T5hyy zT`MS%TiMzQR4v*#FBmV@t4#$MKD`*<>vnKQ+RK~{lUgQQ@5viPb#evxP<;WvV)b5i z1p*yly&%GRycRB`+58E(k4X}w9?|LP?_TG;%p}XY_WpC_S+@E-)~77F_m^b)zG~Z! zQXb4!38GGGn;MBb;`ST?433J1=9d9^z{=9#(mmY@FaydhwwNFr$e;tp%4osv6KE+k z3=AG6r{LFkY>uy1{Qj8z%YSQLotVPse0mqTG_--ssL@$pxz#(=XWW_p7I=(Vszo#9 zUWkBf8;t#l0cnvAT`XOg!}sStNPUfFBr{-<_W-LBgh1*AslQrL6}>6fnFIA zn<{?hyBU(i64t#Ks!?GY^dU`}YAq*DuVZpJ_Ne6ntwdEzwMBy+cK<;5yK%pm0+9&J zS=wk^J@>b`xVYXoH@I;B7jaOf86=GH!D<70#pJ4VLA%)<8%~Z{4*3-2`mph+x34cl zE=>>+T?|;_czV=u^Yq!XXVMCVpa25g=vzzU zk20qdMgYtXZ6NxilYylhBIH&oX8d-(J$mmk+X@70G61CXJRcE|>wg4N3k{y{j3<0B zq;hXwH2*+GMh0g(SHl>HMhu@W(t{Qq9lgA~{Bduxq~3M~9`617_aFcT9GOU|-A&nK zJ$50Smg)!~wt}7e2)qWt7C|E;)hDztvk@8cVhcRbwx|UKQ^i9GPL@T`F~*pFPHi>I zf?EYrJ8Y;CP5bzQ$qj-G#}{WgRaO7^Q>bK;%9cwIV5gm$)aQpX6-;l3DL3^Fn~KWH z%G3iiuYUZM=g5Z>$x$rdjZ%T37~lA9ybvmKn4{Om^JB;AgO2BdGjioOA0WnPSCJ`aPu0O6c!zXj(98(G5oJER;X(wGFxGEg0cE_jbRL( zly?w(b|?)KN-+jpOyDvwz`u@>>MDFHUENQp*a!{{qU7Mf0)mvT_lfaY%r!75i*GHl zh1-R3o&|v3<*+qK30@@g4LN@u3)K#LfmHO^*qU5xdXhnBDR@+Jea^fv59U< z@-aMBKpkLK5ARt+*;dyTvVmA;L%^7UxHvIyZnxa_>^C%)(Z$lTc%sRPmv}%(-8$7p z-2LT|&#~ac?Nw!b3uvZ);rQIddqlN71%Y=52h7MS$)}AtJ%%4BzRT(Q!1l3my6|2N z#{>?y=}e&|!T)MQMB35xtsPK?8}kZasbFV~_J$S{0xL+}3m22v@UgYe=u=7#6({9H zW`bVUsC*`UJ81Uij~nd>AHRL0g0r)Wb)u7VaV}@jQvhSU-OBG-#J~pNGm=I|6p?Qu zVP;FZrB1b_8Ct`xlW^eqRdK*;aNuL^m%E=q2{7c6$4Hge*0w?@K`z8JoKkL=-KdIgKnjz^YCYg{`SXx1svJ`3KpjyrnPGMmGfNE7NtF`3GOZr4Y$Hl);Bl4 zau6i&*_5g*_A@fp?pY70VG$BS+V$Vj@Vo+b53CH(u-&U93zl*C5ab-+!oqA!=a!XJ$#3Fo|@-z%% zAT1;dHsa*OcwACix^sLy3Y>KHbqmaYxsw;K53qv8vsRKgmm=chC1st_fNj8G{x5%W zyp9wMc0fWho%AhW9z;QuaTYh==U}pA>D)P2A(<;})k?rI=`@J~ZfqINRozdDjg9aT zfL_M2=BB1&^kZr+s>#BTKBLw7dI!s;8e(*G^s|FP(3OCk-zz!tZbLJ;OYi0v0UXFB zSX!E^3Bg`RE*3_>1Hgv=v2*QbU?8x?2m{av`#V2l!p8XN#sFvR5_s_yFi$t=2&|ie z?hA8I&JV|vtb{Dt!?9o%191KalR2XRcz;oYWCRNTob+$&q?3%y=PnR90674FtzZW0 z)xAUShR=g|PW~^NPoF*=pPsG)JhFMtZZiBAXx#Vr_k{=H_S`krGr^!|*|gkHdEH)S z0K*4rUFukqP_0tz}*YXnBrPe>7p&9F~Y%fsy$V3;tflr2F8M*J(^a40&d_x*cl z)2&nrb0c^ud1*-R$XJ)oL^0s1~L&pxN%tw#$Ke} zOtAwVM>MUH>tX#C5V1rh#45jC5PTagpxsNaM>(crpf{$Y18!h5;XO#6$z4VuxB8Ufk7o8O!t4X0IQhSGDUNuOry2-^ zW?hdp&PB~*)e=o<0CfOn&90+K`%-SQ0OqHV;YJhcE>2&GxX?Vx|B!&}oScOzcUYI~ zc$iGLj-025C~Z!+Krc&_jIA*NWICiTm>H-JK#_cY_n$V<;X_mNq@UYoT%<^-1M;kYD~6!frJh+ zDys3pZS@NdbhtLK*5Qw5Z-INY$qzof34ylM>8W5nZqgkYI%OCS#1`wcPVUMK_#nb^ zIl#gw)~!q&X}wQg^m3mX@C2CFVhU=!o*#L^_TWPXnlOp$@iQDo-A)rd&u&~juXe(- zC6-pAleBc<7kCN^3e$6QYez>mk&CQV@yCM1%E{r~(c+Q$D<9Tz6Ilten6mw5W6!!%5x@ivU1ENk52kR(l`b?S z3K2@7I&M#Y2j}+WVi&6Muwf3~0d?3MZeLh<5S%<;G<)+*+$}<$gd-XS6_pZ5*%&%V zK>1^AK|w>yO;7g)l*2=1=w**S%kl7-3&;bl3nb|Egb@Ru^2$i}O7rT;=BQ;YEB~w~ zy!D%f`zKQ*ijOq!Qx>z`uoMbOGPG!s>2Nyv9v)>+WJiJ#%1P8^5wK%2$?Ws>a{@mi zzo&@!i6!~TeMYcVC|0LpMyBFB9*cKsxI}bH%1tzFn%jtpAUmJubqv!F+ZfP8-o1P0 zyCAer1u{Bo1wFLP%uhOJ(Z)9}GOZ=2S69?*bYljI!ZyokMUQ=(%v=uoPtPuomPY8A zn}3LBz2~L6MUJU*st!`~kBg251N@_-Bgb6pBAPFt6kJTPC0aFKS+($ZOy4aX+zz)$ z8!1!J_R(HG?;jZnzn(dHO~mttl$10W0=c=#OS`!(g0dzJ!NFqmxO(2BJ6m(l7H>zi z_8+X6pS+%0QDesk1|T;mo9w2?@4!g!1*Xq~%TjILQGfAFWjwDH-N2EC^^==j(gbr! zZg%$1yfk+LUl7Z|6yi$-WF}Lw5D;c#pcC&e)h@LRR{PY)c74G)TYf+XsMjcs1cRWX zaztRD$U@hNPamkM`VWnJH?C_vmlucqO*d!pt_z~6K9_F55{KKKEFrAi8m8jsC-RMs z#^Um<`wrS+oY`OkU(ce~-R7JPe1t1S-%6ZZ^{--u;APmY>`<7Z+b!R2F3+z6Lf0Eji^ z`5aVF{TIb)e33O_PTR|@e}i8HDL-p@HFC-Y=HRWEc9fT4YmrS*>n4fGUk- zNh;~_LpUIAQDb8~a=xQn;=_Lt~ zjo?>ntI&kX1c`iq!6;{aDInTmU~=T=iN-U)Woi@8^JOjfjd`1wnFVXKit-B!r>+%(TJ-2ZGX@O2AdGh zeuais=O#sW`Yhcs3v{@Hx{x!im8YYlgH7Nh!386s+%4vKIiP7?AN!%#8;%k??oFbC z%s_@;;B=h-eEm z*4c<4^`2v_KxpozjvB@1)lDtyZ=IavU}D2?+KA9oawmDvrCaPmWe6yo(>5=39tOUX zhM;-pJ1d4p3;dXv7+)uk5iOSR_aXtyAUp#8T?<&HfV@}|0Ly|8*Gh34WhGZ)E(~8U zlV?Jjof#?^D$j>=K8_y*mRPxiU|&#J*f#(rTs=IZl9C3t(mqTg&RYl((2d_Z?P)Yv z(gFkL?ywcT?DCMQ!7x&(xr#)S;&Wz0LqogO-`J`kxaY;qcv(FmAWZa?D+x$%FenDZ zLSST}SnK)*1|k9h4@en6<@hXB;mqys>Uum~*aND188XtEo?rG0kRa>ZJsIG6o%9bt zwViLkI%NDmt$k%!l+hM0ih_UwqI4<(N=k=>Al(f^ODo;oAR;A0ODQScT>=t1q;!Kc zLk|ow#NFdL=g<9lpZh%iafX3!_P6$4YrV0)aN4J=tWio?_Ta2d1C@<-i9wKhp{-*h zt^Zlj7I!{35P^lqdjilH2N%~AW(jx5a@}9Z&{8Quf52nWD|u!{56EJE9HEjP5fc6w zbnq~8r)HPBEb%N$bEW2JJ%frgZ2qamE52_0q>)IkFZBe z{Il)iz=SBqk|}d@{d|0U9QkNxZOm`3!HLzN<#Px&ewE9HvU#K;0Jo`cXMiw2+{}rE z0-09RO-W8}?wvrj9GObjY4x_*6KYzA%aj=ES5-?%cU|$f`xT0ft2h>0WjxS|nhBs& zq=@=C6k~OM1v{Vp-L9so`Ey2Rvda4KDcZrqedCYyqYZy{5(iJ);kA-j<&0NqT9EE=T7Ox9>7%vPgL8uEVgZ?p{#OqI!y-wD7WmU+ zMK3=BZQXHB`uK`h$bG7Ax?HNs&_|1RQWIpd*xiJ~q6Y*__`!s!UwOF|H0s_C~4R~)7o4$a@ z9@W*wiP`V57oZcVh6gn7z&!RxGS*Hxta_2ukJH({TIs4-4t|kSbtJs;KU!o*TwXWt z%PGsRM+As;VBcH?0w`9-D1hiZIj-9vApsVQC2n;n;`>MERFlHY!(i{U^r z05I%mcAHmkeZ0Mnma%DpCMj^emezx

m53y>Rp=rgCTRm$}3(R5^&Rw^_e>IIHQ zuj3nGAe>Q5K~JjDLnu*=^c}a zbjaBDd#{T{6@WS468PfzxKtXJF6eURG!%=(tf^JZ;>>tAT2Q&3$cvAy>FX;Dw5y~# z?baNl0R8jyKS7|+idSvZ%L&>R7I`Au94su=#!ou(CJhTUxoiemV;E^H23Tx%Mo;%W zc1||O3LmAlPxXV$JX-(+$Lj-Gy(2$!(86d8px2A zaT)r<)ItFG%!H%_Qywyqa`Bl0*H_hy{f$J2L{RBhE|$`aBO@cq^9^jZq8R>j2zs%- z^O5Uw(9EETo4!6-pTLJRYzZZ!5abnKydpl0@TO)Gh!#PEd2LN?bbz4A=$r@{!=!-A zvqRv#H~`XPMyA;rN@#j|RB{373R9Fr#lqfHyF+_x8z8!mcc$Y3pi=YfK?V^l?C*Rj)H8Kq{VJqWik_9z)DE`Mp(bKl4B%dCF` zbNudvmX=#0jBXGxJMCge9z1#vhC~ol0Oc#axEZO9;3UHUTvy6~B}yRb8uP;C+2K75 zpp0M5{AB@*7Z{S#GS0{y2#PHjcs#&3p$rPRAL{fL;Uh|y={5L#Grx(Q0Q~*;$`Uwg zzpVi9pvb+~02BlMuW8h*5lTx5wB->pM7!7@2d@24Bi6j2YeiMTm)L=X3us!=;tz+` za}uyBRBf>l(NDH?pTsGFw#Pv7i`<)^HK$qJJDYHt9##cx(=L;I z8mI+tQIyK4eRFF^Ad&VwL$F_6i9q)Ya21NdeXfac7Lv#?unVY<=B~Qzu^!O;1gbdT zp?C2rsD_ui80GEi!K3%*cMIz^v@c%7oB&+_)hq9QBR*??)N+xcQX^`ixw4Ps zx^X+}!2*_jf_}j z80~-or=!kLo_wmp=IP~gOW?tuqS8{gnM$~VqT;IWp;sBT2iw-x7Qh8SISbnC5%1dX z>V?DByzFoj*wD~W`G{~XR)B8(xo{25ocC-gsE+_RP2Hx!oCv0qI1TjKkU0(93*Uc? zD;3W)f5Bd`SNF(R%4=G(K2i)>Bi!-E5BSL5dNlUoyC{dcA+U3X`Q0S5jUH_T5s zegI@=U@GYbJQL)+J`n)X6?Skw_nRdF~ghvX2tw4&G$ENJQ-|2+;#bw8<(W+N+USBjF(nbkQs@xcUJN>fW{QJIB{XQWX_#?@Q;5JfRSSI)CA!{V>iXP&Z)0e1$0WvDbwP=j^bVfI%E!*eb9Odq7+)10TN z`nDXJfolJIVVQXG_|ab&N1ZOs$z5!0L^;!q6gYrs{mveSg@pmq3V7?c z4#+Yz{F5t1w_}LUooAC15|iIn>Uyq@$fU1}#JLAQddFlvSw=mYuVOaxR|-T|_$&)a zg}Ot&6>>Iy|l3OB0gKiGs#+sj7?#G8Uq!~5(M)^E16KH4!^1As+dfxXU4K98tW+edEA#vZl& zUSzx!ghk^jvda+q?C{(w%Z2f@-y#noGiGTY7wAUyLA%%j=+UTDMD_?7tjx_-)zmtG zRHH(d6=`o-(I%4vaIE8d@a4}770X?Lk@H{cf~;@tQZ>H=hksfNbL|6bikCmmogf}N z3$2vk2&{P9wJG+sz4f%yDBMgA?7GDly5yq10$3p(nE`Ly!1NBsVyZnrdZR}Y0B|G@ zn%+5oI;Uh}^7RUpu==>Ovs1tWN!4iOOntpAI<21d%lx+E`}Da|A3yLKII}AqHrCMu zQFeAP=pSE=KRHz_yZU7PB7nWaZYV*J?Uom7&tl&+Rrx|x(gZ<-ayMc-e6&VcB(oI zia7x+zp9bZ-s9)YiSlSambCN-4F@@wv3BYb^+NQCEb!s?@81UqgbPKw(al|TpfSfX zc^%NpSMDHbT<>#e@J<=^kdhL90Ld9A1Qk;J7Srx1d+pVCn7Qjb-z}gI0ur9^kzr32 zH~q2v+fksu0Wiw4Uzecs>c=h*(9i;`7gS2%s__lAeBAe+Fue*7*B1RbWz$OpdQ4!E zXuLws3c4SsTy5)@PsS%D^?-(P>(K%>I4c1g)?l_w9WDAEcLKG}q>^cV4F;uwP8+;I z#&1tmKj$8)|3JbEA_(%>$JkhKG917;+J(S~h*8F|_q?&!?K0^08rY!F%^7g9d}2$h zpMs~w#fgKCx7ue?j>nJpX{Xx#wlxi__wYP zT((m$Er(K-0K836nl^1~x$+?zjoyJKxeLTIxCLfFnZT;o(nlk?y0$(-UxE!r34jym zBJ^|_`O4m7#u!Ktwx%lS`4!uOKu&u|MD*94=45Sc{nks*0~0WM;QH1zx^V34`+)6f zw0F@58|VUTbxH~uSOGweur~Vu5vm!}R;LsmIln&@kTRlcU~npqetQ!Rqmg_tQ7O;M z%Zo0|fwM~**n$Ew&UFgPTq|N=A7dgcSNr0?aZLyS5U@>lH5ZahzzEBeI{nm_Z*PNN zrr6|9RK3y9$RHR7U<|&D*VJI`9?;sE0QvBo*JQ@e?ru)&VLF;?R2LAJw{`T2&JzP! zI_LpMfqW8(R);`waDX^nf!P_)pbO{6(b8RWUM@gPT>!Rze^k~MkMu>iG zeZ;8zRmGDQ+>9>Zg54#>OU@SDl`%oRPFieFzlDiKNJ$C<{?|hUVg<&*F|naO8`}gx zq{5;iQ=m1Jl#~QDlo>%bqhiXB?PP72QDcXuRiPWT+Cu$jmer|aW10Xy-aJm{{t?$D zL&j|xHTs$n+*J(~QFNaQT*13T2m4c%AppG+y1(g#h~|e>nA{>L^CSd%|0Cd|17m0a z81z#b#t7po&N3bdP9uHE?av5O6)1^Y&M(qf8@z(_Pf(zrB0mavBjCC8b#xp)9b8@F zZA)Ce-fwyc?FRQBoUR!Q(`s5;-JmNqMb1s5b$7B*NpEi<4&j^IvE|-#rOrGuQc`!z z+mS-C*NZu53=*t69S28jz-4;?07-_>%ZNngS5-m#qZIv%&I&tfl(U2e0I}P7hO z=Sv2ZLF?uha`o`N-!TsEs-TC-g)^bs<95x%s&>y+S3ZAtC$r757Z&@pW=*(j#<#B1Kgoh&rc>s)V&HL>z(yV~xVeUUrTaK9-fSN7Z-mH84S{W*; z%ZDD1g(3qB7qUiQ=kWm<5-{?2JsZq;)eF}5OD2Rcw77FEir+diJ39y1pH??EZuYz) z+yX4nyUI=ts9%A;zyegH_bK_JYHcR?F21J#hGYEi!rCb?aw!2vjaH&oXy^y@PC55F zr;-!+<9fT3_RGDOWzGP|vb>1e0u|`N-i1fTLJ<%kIM#x+WeQL^w4pCEGgDJbD=s}@ z=fHBlD*tuEc|2w6(M&Q3wdWZl1Z%S|Eqg(&cF|jHC|NEg!gXZC) z#}sT%h|FGYx-)rFDZ(;}aRw{Fy0;8fkl1Iu$Mln5)n9ChnGi0B{!K2ud#b6e1$8{2 ztFnFPx_BY-G0TQjPwQsZsC#vqymd=HS(31fhK5;Hll1e!H5d+T5rTL?BOLYT2p24a zUZra%Ed=DK+n2tA6#))8sHEmE2$$V#>^Ih0nb#T5%aY1nIqxhNWphh}yNmac;PE&U z9UxDZUEP&gk`&K!SXkKTb8V6tPfHg=?!64vW}qK+>`kS+^n%1j=da&_{M?Y>HY_xh zzC$Jfhl-Q1<0-u>+2*wk4RHCAgprpTj|C?6h=mXY!0n&Ta z@C$7s%YI=w8@A zRKWIFE8;_Q?aA)*N|Vo@>QBG)u{flj&{EJnySy)B3qGbaaR# zhiYquKzSx7Cpf4gb|vBE)lJNr;aCg8X}HK7(zdfFBo}-pKs=Ah&{CYXca1nrXmG25 zzUGMdDU64zDiyn!Tu^x05+AxS)@1l`enzhUqgoYmL+n)L_l$NUYyI3sJ*bf{2k=jg zzbzj7vd}cqMoSM+mbWWONikrw`HRlEoT|Tf6Pjo_`ZBvF zd!{NKLpAtnzh&rGe5!rH_)J-|y)fXse38@ZEQSdrdFq9p>!|^UKOf!XH#J?zlNN}h z*Lixa{z4;LQ_?-@JLhj-*QqhMcUagj;RNnj zwoY{{$VHn~2TH?sdrgHr)nNvKlr>m#C32kqR>SFn#htrujP&%?kmCHJs!xyJZ6Svu zWMU4lJbW5ZnXe$8y>`M^$9S6B+I;mS?XSWl#BZ*z1pJtb2X=8s)Z(mb_2A*f4fg13 zo3x1OAS2H=*X6&-0jFSiFrWix?yMJ~B>k~RhYw$x%=eapzoKF-jG(5w|?%h4(5Z?Rl}CXI?D=N;aw> z7yJ6|H4Twaj-q#5n8T>zW>j?f&?ep8$opMLXXzP46y)ry}qN9c$3 zkWr?1;m+)~Q9|=i31UY-Lu}t7ID2Vw8ZpORkK=Sv@wWooG9LF+=2{NKVwJ_Jjx^`o zj=WDUMbf6sInr%x>f7*Xu#IRO3yxfL>kM7%%x@G`m-^WL6RG)V)NJg|xg41ySK$V$ zug_d)TOmFRe=MGdrO#Eg8*95mA#Y!U135;qIL8$0s_7%B%1(fN`bOPr5~z3T`+#uJasUG#r*Qj<`#NG-TDl5 zPOo3kTim>8CHi+%H4X-(u`ufX%9SOqx}U{F@#}@1_l}gO3|#A|(zlxO{P!L27Y%;j zzqB~x=|iJ5$Mn)BuMHFXcM8^D*QGkdroG!>aC(#b>9qqdB|iDii#sT}boR;$rmo;$ zw^zEffVpdZJnJ}NqR-d+XJ3>qZ;%nu{%$>c0k0d7ca%pZ&vVLpn5Ql-#9Dz zH_KfWZ`TLuUo~;>9VDD_c1b$bDv}07yij{@ZlbT=^{{8jUf%NOcR4{D%SBFluHkXx z?2-w0QwLAKhWL$RGTwPi;vHFDwX*m_#OKX%aq+wb_uo|$sC-@G2ro-fxtHJ6IvX5$ z@vw?Ly<&s(a^QCBIf=SF2GJe11LZSxqs6VkXV-O%1LN;T#;pnmUCHzAM1~g&y7u%3 zQN{Cqj8Gk2&=0GZHdXl$ff(mn&UhTPT?j6q^V+uB@7yGS!3DeM{3OAx)%Ahu%eL50 z_zOh)JKV!$jdy!ZKoI~=o%$Vdtk*_HqBfIlWvNQQ6L?^1A3vInG+EUi?z`3)3<+eae(t5Wk&%B z81UH;ZFmQA_myBkTd4iKM8ow(1RxG8fXO8xDe3SCX5)1{5)LGu>+o_93{Xvvn=AmQ z^2UNsGAMJpdZN>wv#?;AYz}wKIm3kgug`Vr?5{o{cQMc5##Y0XW`Cqzip9mxR0m$>7D!9Bj0-dJUddQ*#F?r9telX!+F}qE?o1cAgW|K~V zGvzcV>nuLnaW^n4JhbC}VpDzy1*8s%b@|!;Z+JW@fo|BH_@|n=q>wYNY40OpzXhSI z9$jAXHe6ih5~j6sD7DI_F#{z;R9fMCdoc7p_gXENbahnsQ#GS<9aCRgV(IGs@bLR& z?B>P>7E9MQwfFC-9nQX+jFx?y*N;MRWVQ?@NDLuyJJ}7Uo3j&4OdD#IX=&SZ*K;rP zC&Qb)u+EwLII0C~ixY%y>IRaXCprgfBDZw5qUXG#KM)2)96y~TCi|llku3dpKIo0RN3w-_ zfT1X@!F~`+)DZ=PZ~S}Llp)hfq`j*{0bOx!oKfnc*D#PmOMbJR4$1|`5&#Wm#Z)r9 zF#$zWYqMCBb*!#2I&3|rn8ugd>O%nRT9k@Iy}fCqMxLovRn8cHM!5mgLJ1^ENDQ;F z?>1<1W=Q0esIk!tBV8a)86Kb1V>heN}f`7fe*jIjMzeHqsp2(f4|1 z6o|?A7X%W=#(4Pbs$y39`uZdR_2aO>3Qois7{=!mbD>xt{euS={1VwV{7GBHcD z4jzCHOcnLRm6LnndpyE~JddGPSg-7*S?-}MsI(k_MWmErhg@m~Qp8^M^SrwpW*j z#%e#!`{8u4g_wAxQ17lD@-AsYSLJyo#rE2YutRwat}+SaWeU48OIe+2UOeSMms=ZG z=Jp5p{Ip7^0)1S<;#8AstLWSSVu}1woVdI_O-a6r%w6cJ&{e#YW%$-caVfliGH3ZH z97{G~tS`N^LO@Z4qlnUTV!zulvE9Xs>l5`TYiXsw)%-%t?1T)9AX^q>N5J?u1RlZn z>_>*(6c->Uc3Mf#@7`S{eN6axEEScs7@d{n5V@A4`kV@@0J$|9nUJuetTQGPLnQ^= zXe1M@Bgder&j<$Ns!V}KZzrp(%SXe&cVYRbJq(lX>C;Q-_HBU^Kr<3Wm6vlwMD$YS zX9=g?dabKV5Dq~9n2;urpFp!IA4@ag9Uki14cghCKXdRA5LOZ}xK_H{=8qXz${Mzf+SZGI}4eveEAwZ)&am%HUi4$oC)mnBy1u zBng};;#Q6=zmMzi6PJ2)A8?yyBp+#FRz*n!f1B5mbk!!>EPY*Cf>?SxukgNcum&%I z$n*QN3pXvI$?nl7eqpYh1Uf<}X0nI***1Z<9il@eZb!>^nkP{j^eEU}1tgX&dr|1o z?yWbTCd37Eant)0HClZ9fSb{u883~$ma?;jsR?Jpx2U+%D5{UyKGIas+{%C%mDU?5 z{#<^w;YD4ilyNjBkSNphG^A}|mx3H#SJ>S0>$Y_Kimw)__mHsWgURrocIW4jul9`U ze$p6}_?@s}`227>o%cA}spe=(RMrr3w^i}KhWwa$1MpLWg%1_LAGESEYVBQ?lxRUN z*EEIryR{{*m5A`g3c1y46dN1sQN69|;iW$m7|mAdg|OuGux}aV0<1%CQSqz_F|n4X zr>DX5W;g#y_;*}6=m8R0C3X!jQcUi=VoK0U0;goLa-Q<~yq~wv=Ua~X{hb9k7nY|_ ztw_?yr!}M$E1*}9WcRG99+LsrUMI{{sX?aMBD^42l)!_l=AtuXLr~OHdZ8TN2CoB- zOl8=ZRg$;^RM2U#GnRaCh4H@SB=P=Ij>*<@0%sWdhUV7v@FCwQxmHwlT)yWR`=vj7 z$&OfGP1Q1eQY;x;9{zJ`;k|v-C>_l4tiRjN>4ja^;PcTzSR>|y#;(6#3s2cbYkHk- z9!9CWgfUa!L1RS>C56h7&-d|hsMj_Re6rO+jJzDIDhWp$b@g=XY@`xUqmcUh`(GY( zsbB#30Km0vZG+;WrIWdZhqQa?_lk>(w*D|oy=#)r0px?aq2Y@1;k>DW4G^@;6(gQS zD_y627T{BpSbo(p&2u@1jG!JM{aukWCCN+Dn09n_06-s)xX_=g#Z zxtY9&vxSie*Atzo__{oss=n`uxCOpkk!-FwpP!d;nZ3Wfh1;CDTPngZ8$(G^oza%b?@q`!YOC7+%1Rg}+0f+iN$KqG(y8 zH^8uwm}UH0ON$uDk9QWXG~y95(ntnD!R~889-h!2Kiq-m)5ymgsE+QF5%vaQhVLK% z*?(~o$-u%w8S?G0;|B&~yxaVH9*U)H>X0Ys?wofcS(e$23+`Xst-+?Yo1L~mZHZ?q zKkS5ZRM{h6=~(7w1ktH$4o|d@4TLJ;xRsNo?}w$aRnSWf_1~g-&LAsdBVmk4ybq_0qQ_kdEng(^GedHdux_<>57(CJgPFTr1z8WMfK7Lf;-BCr zc2z$Jwy+pwY*M*ZZK#c(ij#`nm2p;byN$hZvTUEp{kP_Eg8uW8Dif|Z%vJ~tRKz~pnRupr(*N-OoPFSRtvF*zE3~0(P$e#x^vjt7?Src(W;qU?m5nEy zoDw1G%fkMhZeFY2Hx8anBlk7Tcsy-NV`s5YFB;g@-&j^Q{wl~UQ)F@<_4V`HoaLtq zljsC^yHRT=m|;ce-5ONC=-<2i2~}L)w!9opy98>#DxXu8v59Q}_FIC|&-Z){jJnuc zZ1xbFG~foaB=vqy8t;E?I1@&9?iRnFfl5Na>948E8+&^i;C=uAx~id}lA2oOm3#Cn zfXnLF`TiQA0iI1+;B|&izxYL#AKvzovQve4}4Sw*;J?QUeCXvOh%vG*}?| z2r6P~r&`Vx>|5PL@kshXFrkM-rEt=}n`94sKq>m}`*VET6_tF&#-OZ#YhpR5fS(X- z*SnSk4XnVtU+g1y#)VS1VLP1t9NdVD*zu^H!fy^%#39Xvs?5)r-KtJ<4fknUijSxT z&2sfPxSQ%fq+PsIlO;;@#w+;LpQ1?e`7Poh_2}Q4IqsfEVRyVNNa~p2sYE$$-%r~# zu!4PwqjpQhOG9s{`Bin_=2vv~Q;Lnh{8pYM7e^sHM#PJi%57m;YZ@aD_AuRV0!PZgCeF$h?z+=f?!SoMv{&^4s?Hfz*g zY0u)DpkJocEsbm6V{(Oa%$iP4aT*83D4qvMmG(Cozi)UV4eP(wW93R`<*D9FrqGT$ zb(cl-x{ADKFd!{_YZ-8tSO_oNB?<)F$F1z5S&KiOAV(&)c(*5)x9Nn1xY4b&o-Ty3g6Tcp=!S8!Z2s~H=Ac|J3}!3qwt7DR{sYT} zmT7CA_k)=ty)v|Zo!3{``nkf=IT5@zMpnNQC{wuByg|%?7Q*UuFKepNCHW1<$VQgK zTkx?tZ@4c2!@*Ogl&f#w55&aA*U-`$2*n8iZ$h3Y%KwJ3$f^ugoIacKJ?M}I*igq* zWzOek5%Emi(;zCsnMClZ<Nrr$&aQ0*e;ee(*hLL!?#D{Tv zyRKhD9kqbK&EmY3rOcI+!ZpvG93A?JmCeQ>(t?;vSR7FM1WwHx@wU#A{p$x=+1)@>;LoilKgKps^0%bqgp$GY>)OfeCz&y{2>FgTOSPeRsQ{wj?%NQ z-!R^kojO3InUgFYTK)4vWW}+<`eeHWuu0fMLV9lBCx`Dh>))`&*;c0LSCyczknU1k zx8L%!Y>!sdl7v~ktSz1%MkE;CWX7|}mQDJP2e>vchxAyF!GIh50qNh{>^=9`U!=)u zR9z)zaP;Hvkmc5;DA7NYdm;x7eJ01I?TPkG5SFo5v6^wFagw=KN!7J@GVg8%RALcZ zvSU%O^AbOKUV-%l*-o=uxiTg{a3%XwwvSrxJO01xF|aVtHGKwUlO8Qj-I8hVrO+L_ zYF-7>+#sp>*KeGbRf-Ty=2MsU zsl(1BKv*yH@9x+=azOlheB;0Gg?{P({%5UlEv60sup-$T-vl0&i6JMYELkRD68wJv DaC6T? diff --git a/docs/source/images/success-dump-dialog.png b/docs/source/images/success-dump-dialog.png deleted file mode 100644 index 94144c85718a97814131f5b28a4b1ba996daabd5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14629 zcmb_@Wmr^E*EWizgp@Q$r!>+a(n^Swba!_%0t(U%(w#%Y(A^ypL-)|#J@4^({(L{) zf8Tpu3^N?g?7h!kb+3D^9r9IC1{0kG9RUFWQ%+X$8v?=$FW_@7Dl+i<=k`oD@P_6f ztLcn@fG6c#87 ztUS%;cTdwb^(rSldSg!JjVdiundHJENI$1kUc6wUZiPm_(enDxJa3bpyh@qM%4*ph z{qoGSUGGcs`3SdZ`^6!5P0c&hfdA!(hkp-aMTK7#+9jVYe#q|lUa~`DMyvjaP zgRGf8uKPJXmt2jKeV)+x)$++MwNq~o2a zxQHNc+I0De#WXj_zlB8a$x6u{o_dMcZyheSl`iZGHaYHFMSMv^^+3#WIhco|X~t4= zrHl+z2hfJ}wY)?9q%z@3uAp+}wUkm|U2(Ju*%Nqt@2L-4WrpZvsqHh~Oea2iNO88< z)k%J)-U6mbNu-q+FNM%Oop6vDG~l{O2Io8bXk*c66#QX-}f-t z!bk0wtq~TZuLIukh{?r9Kk{{_ksKQ$`OaW$y!{N^U!x%_psO(f{2%rG4^%JU%3H-( zt-!;)W(fE<^ zR$Boxn~&JBbZY7R7*_M&zrdxWlu=d1#|p*-Loj*`dW=G7+g!DcjI?<*TT^IvBVv1a zL(sy*BR`dI>iLARa?=XNiYw!kGP`rsSK?P#tiKL$NWAb`!ry{zI121e(xexw6mpr3 z5N&L1yqtbQ5xPbTlzB;qbb&XmUO1OX0Qlc)EfLWN65Kvofd7?HX4%|CR3B`~lJj|5_8L zKa*iJUnFiHPfPK|R;GUn^^RG<4x62Pl<>Vb6>F|c#9Ba1x16G4*Up8q6{OmH-0$tv zj?fT!LVu^G zn3$P2YQ{xr*w`ZHYs}-);$_8G)}_nLbFU`r`BI69$q9Hy@+}V?n=H+FqHVa;QyEqd zHXHiCM4>uQ^e!lKDzmcG@Ess&Nhxzc9sZts2;WLV|7yYlVrYPM5K{VFS~_b;Sr}Ba z=2}uc$y?>tEPg(1AX{=@&17U}H@`ldClhdb_2cKySAfi;X+vUTahL4)F1AOFdw%2i z-x2h}8*Wf2eWHUY{a!Vf#s8V>vz-2*HKFu7s?2R2GEsQ0u16&;w=w1xav4(ns_&@O z0l0#rr@K>pJy^?^j_Rcu+rUZ{3ECp$Rd+qewtx6^Gl;38&XV={g2 zlCoK7;mtc!R*uo}yu-i0-izop+CGiR9no+2)B13Yk~mrDPLIb%tYr0>tD03s=i5+F zMC$j;O!&*_*t8y)3jHMHi#hAt*B?^TeIKwnZuIpxoEk|@7Sl&DkP$cgbq8Ye#nvzG zQXp(81%~h0vSgxMf-p(@D4$P*KMu%9Nu6~dVslvjrM3A$TG4Wj9upITK`w|NSL|i% zxIL2G0)KuW8xWLKbF>h&Q>3urnTFh6W6pbnQ5Q_|p1w|AYO?&@W@QwH!yn z^Qq7Tb01v0%)}w%DB+KKelOt9UN2x+D8)>J_;26-;#slaIUfkTG2+y|eH^Z+Ts#bK zGoZy@dhpisx~ecSr=%7rCU0+lQdfU&NdbXc-{f|Fw9;ZO*{^7(m0JRhpA51yuC-!| z_8nbMl-p8US{Ap5M5FAcC(C{NCgf#qR_!^QXjT^1f7AmjG1#9j{%6-SU=5T$Ofvpx zVs5jEGHpJ;`#py9iwn>Dy+Y1Z>*K(vu&~Wgmh!dv9lefCH=~f>C5}zplZ@i4lQvz{ zYGN!>gXq}#wVMgKclntQxoN|a z-SgxALBsO%rv32j5mgkWfDa?n;9$$?4s>8l;8jN(qGrqOVVr!+rP1^Cn3!C#O>cz` zB&b^^@@3^t-mIUhD(%^sP{Yai9$x;3}X z?{C7n;*&Uy`%dT0Gm-AMHa9l@a2g})Ho0`}xtw>RP)@XiKtWjKq2&jME3K)Ik3K;d z!~vsb#s{-yX`tsj9j8G$;j8JXhVlF?d)uPcxodhF?7|Gxhu-`TKRymXT}jPYq^Q81 z*4jd0z4A^@DAm{-mjSIkNkr<5=W@ zk(GJ-+56aJuo_mX*Bn{RrEPG3?u3$BZ)3bbpke|25R)KQu{|(pY*;beXtf(H&X|yS zNg!poyC(kFa5=r&ZzotXF5}}v2Dp6Sd4)K9);j!koJV;XL%a58!1J}1c+T4+okmra z2AwZ6e9qH@Y zL~fR!Y+7#?WJpt!TwK?JgbEG9E3CNbJ3iq{HupKR+LQd-I5NxVRcWnpptNmhk?jq7o34 zUywhMEkV-QD3g+}m{Nd40JHa8w0Xv>&S6|~9vA89??*fxWXPPTF;_yyBI1B zd*FB4LS1fl--(f-FkEhO)p41W`T?hQ2Gq|^e^bZ8EBWmQJk@3d&xE)6E7>97&5KHtc+J@}!ua(i=H-zNyW zz?UD-2F)jVFm<7KFzD6e`GJ>Ut&;IVf=VMiquJyBE@@zR7~9c0O&jp0fhd?oj!SFe zhyre`6`E`#L)GESc2ZE+oZQ?OL?T{1n|%?l<)+~K_}ySNY=s(ud)e!1b32N~aI!_1y)Wn(+JzZXcH2<-lS|E1 z(T}sfK6kc~T{-n+EU~Gpt(fwwDj^sW-+0khsS2vPs;qjO3M zwoba>zhdCVCKDdGYxOqdNWu2ra6QllBk&=<&Tl}TjYmiks5;ST?Lqij2 zyI6O2+Kr7z>`C2h*R)69_IUoK?RMk!ar22N1?bTc8H4Dfqa){3p^|yWj~A@EP58N! zvWA9K>fnT}KeG`kt6D)CPjfbFGlHCV*wV%pt4q~j62jho1AZ8$@l|n)2dmhdbL_&} zeC?mfqA@r&F8q#GB&lSI(!G)z-n+?Prfys2w4PY>BL+;kChKgC*5ENXIFgc*U$v|- zQxwI*+92SAXLU2*ikhM!%n~*5tK-HCH?4ZbEQNy)wDfh^CwHxlUVS`iiiFN$aNH

R)AVese5pS!z^b`957;nFnpH8DLOY#S~&&T6ew2cWOtuDjH=G`HbPWgGWn zeJ@l0{Q0xB4^wE@*`}ugoMPH_=ty0Qu17^n>+^VqNaI-_DdMug+Bmjc?Cn0df=Jkd zgNcbLudr~c+1-A`jC*i!5Q9Sa&)nR1(dS!ZKRrm0x@{~6k;Fr6@%TY@!|CntZ9AIx zIe4MZBK~cw5_EpsfsTpu7yF2k>X33-4tk^`^eF{?W zfp7lJ>ZfdhuQQA^?4$dE`fVk@vyusA^at2KcmFb$MoRGH5DHGx_YP!=qvx>hQzODa zMh^?U-B^A7iR9$W zxkER%lX+m!w;GA-Qn9pVitPbKMU2d8icZeh7f`;{f`$fDJyi|01W0=+7}RA3Bryh6 zl3eb`Ivbmtp3iqXmNU$^mhquE9Cl0mZ&|;0Z1jfhP3EFV=i=m^_2@bx2l`i6a{(3~ z)r%W4NanboLn4_ga!}AZ*mGFxCa$0I*M+A)8%m^bZBI?r)G-l4WDxM`yW*W7S`YPhywVA^?y0iP(0JzksAP;z`B1{+kAz-B(dd}mWJ!KdO2S1Drb0Z6IVN9#l^bm zeI;~c?Apt_A6x8w@d4JY9Z74g14y%-m(@qKV( zW@i2!5|V8`o}uH=iR5y!k`A$konVqv;c?e3wYPGp>Vkq7nc`@=eY?GpTEe<%dfdDtAGrLOhQC+_5TPS1hjpYZ6`i( zIM+>1?>^qYp#d`Hw9&)5Z>7C=4LSt3Efhem0j!~Ky{N+ql5v?@bu`wX^jz9Nq#f67 zhYcTK?|LWa!jo!|&nQW1GUQ7_S29FZUpSwk$b=f;P+(+)_d7JQd(%x_^mZh8vCuH| zH;q66ubJ~JdS}Tv&|tM(U|XmXbkM0W_40)&kTNTXCz`V2C`X**4^6pV`?%}B0kTqj z>Ro_V(Bj9r{FlzB{cq_!o;Vx+#@u8l8Lul_tXw>z8eIf}tKQQv*k+}L*t(b?thXze z67+lV$PC{06rpqB3`L>z{Xy5&HAXH(YD+9y5xmj0$&R?d#QrpGi5a0DW|jrn3%Bne zkWC3qYepK>Lq+EHvZ40!;VR15F3)+#Qyf2y|GWc&2NMiyaO@NcNJ>dL9?n&5m(OZ; z14+nO^N9nz^(NToT!;|zCkr~Ne0#4Sxm9cU2;)BGPi_7jFmWj8cKDlC&Zp*-6dfHs zrCHECz0LQ*sOo!4Gf6~w@2l3?DzQJ*9Hpt+?gOOq9&Em-n<-I~xmww7q`xR|0v%_9 zWlcRT$j4+94iJ^gCNSyq&W+-I#b|aiZ~v4)4nh}9`GFO`qY|(k=y%UP)OP*$OZD;= z-$$fByPuBcZb_D|k+C_ETENz|JZ!;~NUQ&OH_?LDoOq}$6YMHrNq)a^;7r_S3X&;d ze2oD$#yyK{!|d*>h>1FR(IK>Nw)OZVTkbT?CNV*?5zSo6h@wujbJPzt#_)2&cIo|X z!roEoj23$(2_FA1%7Yrff> zozm}=iY+OOlQ439cF_*@?0r&LS;@hnul2yAcYpDv<*qOFvFRAvaVj2&;y7=bG}$KM z?V`IgS7kin>5bJNMTu?c6O2XvhtnDvz^o_+J7eiS*MsKx1O&fYBA@QBjL)YB^YZhl zhPirsdmpQ>3AaHanJ5%KKSoC65uVTQ^$~8@;Gzb5vH2}m_4UB8C?{i{d={k3-m9&& zg|rvDG*Pn+m`c14#q-};-%@}s&$8CbwClI8`1E%UD%#ARp%>O^^%DJ9I=n~B0I|ZE zItt8v*1Mx$>G$Mye|6CBi@ntUzPSo{J#r@%F4=} z3%u5M=V9z;9*RCz;{yY0e}~!fRr(cs`g*^8`_^@ynOL)%DupnT#v2zBNB{B^P;7)s z(~GxyzOb3-8zmDH+JBaZh>X=?ROPTcK_&Xwj;%b?cS4ONGmLg$ryDaA7Bh4%k)n6R zg&{(ZbGIf)tArGr`wBti16m_Lp(UJ|R;?Gh`O*imyrND7k9g}t)xH%e8(UZy!*$(u4Pa97_{a`;dM%d00fQU5l!y9%Qz(gAYM;S zPP!b-Vg`3BZ{B~2?a7T2`3z(L_V6cLfQXWllXKafc#$+raD7cCcxEk(jC89 z1x1zbr9ojWA5o|IMCo{cF=YD125O?*EvAAb)J@Dr(mD?d&HgFPH$bWt4kF!F~2lV=N)A`c7`%vk~<`ZmG;mahw;{%H#o$d43r?; zIVBpIh^=cOJ8T{dTs*wS>w9a z!Wy$HlD4Pu`i5n@0)@;zV~__%a5oOW^3Q4zt=vXuFlCOX1TA zM8?myNn)uoVQ5~|MlnN?!NQFcnE{3{Z`tEDME&_Q-w8P8Vtc>P{fEn+s-TJf+81)4 z2A9K4SU$dF6jk+o5sG69&G`t{Vjh#?l*+y)LJY-GwU4+cN=KpEIg*+`lQ5`Mbs{=x zSPgEm<1Me446y7K>r`21pHdF}aE%2QwA1r2`lQ(jg*#pD&dSyWsBDASIofqR-el5| zK!)GMm-1%am%Mjgth2p5SYBcVUg|u=%r_V9twknT1#Ln^}MejAAi7hU>E0Lc5cA%+a9i)y`WVk z1noBS)g5xq&~jb>vwXUI{-LLS_hd+TY;5e5)@l>r?KH~U*S*+UPP?+QCYXnFYhMQWe7a-dUgZ*x5ukTW13DiN8eW-9B zDFNW4k3_ljks#SJneGD@IyQ2W+B`K7a(NXi`s+?IArqf8d9H|FwG$VHPHHJ^fX1XF_ zr1niQSmc7!0=~Kn?iNb&@)*|8a*?t#gydH4`8HeciNcW0{wQOJ*4{!H%U8JI@lsV> zK)_21-$UgB`SeddK980aQ+wxLt))6uv4-8jhFqx#yGxDS#l^*}`fV+2%YpxRer!26A3JcO z$nq`)eo4+w8Yh4=Lr} z;o&B?zt=HHMOiJzV0^je0k>6RMM`2O0xskur&L}#&7(&;F!mI z!S~ut;lR=i2BN9{Em=B}L=Gsikn*Y8X9t3w-oJfqYHG?GDK=l6`N_!07@+}Hr`>Qj zn+jIYha4f?UmpzbPUgxfD9}-Jz0^z$iHt0FU;NnwqRyp$QBoE>wbye{wvOk`ZN(|h zP6*3#BMzmQLLT(xF) zsoVR$%9VurBK0PAN$ zJ^+wof#>H=F1qH!+wVPE_3G>w72Exu7+D!5mGSFruWrU!Lc4%KW6YI&d%3AJI6B%3 zbDIQ+1H1Ok>#XzF=;*h*-BGtbD?2(I_b>mce?tTRb_;jmw(Eo|U?-#dYT&);V!WF2 zLTCXz2y3z{t_by^XPKfIEK zNy#2NaZFFrWgQIMp?tkA`xF%}!zYzycJxH6{h~;;wyx0Ukw+@0Kkcu`2J;Qv77L52 zRqcVhM8fuRu5PBuxi-(`)bnvwqo}vec2QPIsZgUr56CGH3#Z`Qa}AC(#3I}Shv{;D zexi4G&tVP#R-k2IsIge5o~_VV0^5O%zX1WSSb@lAr2RFxpQ`VkO_hX3^fjHdF{7(BlO;{3r;MrERwoUAM=iCNY6my6UoKKQR!f8IeIA8CZ$qG>WM|Y(nCuirXc^entp%&bPfQdh(itRpJodl1XZFXae z(h3Qs{*C=MbOfulnqe+#DLL*+Y3kiy6hpxxJ7ov!w`X~JUmt3gtw`s_06P=}DaS1C zt=*-QK?^#9_d<8LT5|0rL|X`oTV9zEFXO(h&hBfLP^4dcJ-Hb-k*h`3XtP@-ck2}) zR-AyPWn_NYa}oU+i$=h9cbjo~43R|%!`wqAa9?UrGYZIuN}9=-;0S-Hzcyol-Okk6 zM3D6et)eCw7u%3BQCbzurxg*$O0it0NBOp_;t{Q*bzl}uA`=U)67$W~WA>!>i**s; z0^Qyp{)o5G77$X9{d^0Olrj+zRjr|EyTfeE%m5CUYF4tJEz=GzDKWVo+xm-^gq$F> zUX4Z+A?;M{Tsd!>SCIF&0(kD%84O_|A?r<~<;DkzWm`Kt#vDXMLUybaQNg8%nm^zX z2M+vyM2!Vc;1|9Cd7Ye`9Nuo>^Ho!?BI!aeeWyH$0ZXo#scpQGOEk;BXELv{vxK{6*zXb}U4&a`@pKs#Q zY8n9vKGjj?akVrOv)w3u&bF~P(UG`d7Uy8xIXn@{#+Sjxk9?U{l=%W_sS;p@b7zQcdW1*? zF@V6UY?XyB0f4bp{*ie|e7?Cwd{%tEhRlbe7VBw32>X*$e2z((RFu`P*@CGMv{uFN zgZ3V%ad>;1>_EN@NBINc3JxEStga$GA%!FWNRK!dK$LA$LDk+&pVdb@wO|Ib;zPs3 zA)%q@P2ilCmb6yy>)1)|z%p&6L(=-i(F2fgdUB1~`S$8c&*oXB@1mQY$1&3L<4`8z z6am3o&a2R39lu_fY^HJ?) zstAD4W(3`DX8!qLOHxywAq6yO05<}9Sz23$VM+ew%cDDGM56-+eH>cqXdghh+?@}z zA1r4A&Kx;zuqQm3yWt3ApIciS4{#~bfVWzs3Oq=MtCo~h8{MH7=!quuh7m%Ao&YHA z0VMm4P74V-pzf=GEH66xpNG9AuN~d13ud4!4UhvHKrSz(j9;qG((HDO?n3zf-V6u8 z4NIQTbV+IHZ_)Z4IZ|PatgN&EyZlxCy3;Kv`%S zhd4{&IgMcIwB7=}V=<;>*BxC;@11vuyC*>7iDX;42+?N3x8;^5%OrwE4>6%}bUj{&_})B!8pduR6yxMRN+ zmlx-2Z+{hl!yRTDo`Vkd79cD#k!0%$V(ruvX>N(QzW*4%op+Nm0K50@)$jjvc26hF zL*7v(M#1b}=ZOpFY;aVUV4ZB6anN|t96K9qM_YWY@4`t0G%S#QRIT-}viV}bUSDJR z-_z{P|_MXW4FhY(6zj~;EbQRjTtbr1vi&jqb6OOR-Y|iU5%+jye^O*3 zM#ue;)$&;(-*8Q%?+nS8k|7PKXbOS2g=2NbB<W*1=^*JR0(**#GOEc$2+m-hHy3TY?_iFy~h=&MAn6l-{vOKcGij_3)aQ{cAADOvk9ng1o1hDwL)Yem z5CUh_K1&**ma!MA+p9mSCp-gH8JAG*Bt z_YtV~m1&+S@`sl1a?>S$Y3xizvNmVl4uO-KnHVYk z0@**=iVEE=F2DC_l@Q*-sFwfi#O1!~i(=n;hlSw2?1~~Mcf{}Tj-^zBkDWb}e9=8! z+Vn{^b7*xX1&^mxV?2E5N5M*y{2vFjf9qUnVgKH2raRF2mk)hYm`$p2K%$wf8=`n*TOF}$MI)bFw;L;I6&eeQk z%B0B5~*s?b4O_ZpHro!E{h=@~1d5$x*;n ztQg}=9gFhz*_yxd>aP!tZvcgdRMg+i`OtbSQ;^ylJvc`63Mr-O>@WI3(9ihMuN)p8 z7U5gR-gY;^Pa^IJ6F}EkB!x(y_lYn5wW0RnW&M&9jc&8sdM}|qnvc`J&b26z&mRC4 zoIgKM0-oCQYKHK8r2!6rL(PZcL&8bLRJ#J6Q-l1^Ir!lvBJ-{-9SH+3_zDeJe;(LU5p)Ibfnt1B6kEJh3!r; z)byLi@O+^ zj(P^ZCmLXy{NB(V_Os`73>}KaalT$bf%W#G@Jo1NgKa}du6hK>_Bu#`z10|ZmwtY*WO?pKUXm`_?M z=vqe(UO*OPazxj-N&4X&RQsZD zZ?^0;eOyQcDPOSKPLt1RC&NE;?&+CrQM;4t-gBvP+}tJ!Mx>>KZ2F@duTNxm1NZa~ zRF7;8;x)pbn?2WmB_U3|2&V*50pbOE3|DWmX zo@0sn6^X{Bam`8nV)f{{degX+bqw*>iv`BA-VqIw;f@yNFc6s%_L9sN`#m!%VS zRZol3x=y@XkXuaO zCLxoHHH~v+(RJ3U2YLlTVmetO1%MxDKwz;C+JhMpewFQp&~j7 z&^|{96mKJe;yNYhkr-$#V(1RWmQqvmx;gIEwja&T$;s(E9~vg-Pgg_$Fcb_1$@BmU z+Ajc*gxswKZ7(DA20t5kBuOTV+>ubMhU|rs3BuUYvCwd> ztCcWTHL{R>!#WDZlfN+ZQR9pik}05oRT#Ql&e7G`aydK}@r8J3-}Pb85xBnJ>}jeH zJ2W;@qJd)mbPZO;!Y>w2)>^$y87j5);9sn$0@_wkv@ZH1DN)|h2_$F|Z=m0UOncrJ#RQWn#ztnJ7isku6oHFrihU>+hG&UbLZyeEk=ZiPop|m)b@pI`F z=SPZ4-$lgSk|L=k!qIFXmn!|*kD$dgtqI;&h0R`ZwM%7&-|)AFA`!#HHy%}gi8A4c zPYvQq5}`4VD@%AbmD9}3Tq6BlWWKbw&$12w+53)4?u}t=rFs#=XyK+>=Mg5G446!R zm5Z4Lv11`nFH&1gI?a6RUYs6q0kDTwn}MreJfaOZ^d8CIW&{+V%6V_<^_OSL%o9F| zeLrs5tou07epS#;n!|j1(sBXv*vp50Vgolc{46a!6fD$ido=HhYJVda`@POaYQPj) zSYn#~XKuUpp>g~&xSl|Yin^<-!~cnxBTIjRAK<#eF;-UB9}DcA(>o+5_&A!s?7;mT zQMxGBD%CdiQ|?pu>7uHwI9SL`EPDsXd@RfM<-h^mvFemlNqe{h!=ohh&#=oTxKq$%uC z2$wQ)(V$7X;mkg$Jgcl&IfES0G;+;>i@ZDlRS?istj03CSP>J;Ygt-t@;Mk4Sn@hh zD6;AX^&4!DfGg(@EmHbMk~Pj&yeU7(Hfn03D61s^mD@_osYJoTGFyE>nbMWX|3fzc z+Q8NZ_mhL1*}3aN!^ac>;D@u}d-=hiEAW)TF$3>>=%^qnG^)dj(XV~^SX&- z-jVh8`ty&i@5ybJ$R8-rl#geb!MoVG%gXr@RF5sp^hm@vsnPK1rJR-dZuFD}YD-wI>eb$9z z`qr{fRxKkzI;|^bZW=SZQEOa6wcn!ihWZVDRy|qGbnN)oD>kO%JQ7;yWA8oRodW&7 ze=f#PMgg}WKE-p~dZQ>EPBgSX(>^U2HNGP@m?BS~buH>uI5k+&Zf5{Egv+DFV8El# z2$qeSA--c{`>|;2N8cu(9-7ibqvnZ2kHQQ=axAglDD~%pVLM%d=ez+80udgw7-U_ z-nm7D(<18Pnqm=vdt`>fmH4s;ctAebxh~|6Ys6UN@`(i~XW=*{VwBr(H z9xOA1Z&5>7#`%mnKW{CniQdh~xlM-5%K0n6juHrf?R1t4LJL#Q>B@DUE7=&hLI&Aq z)wx2gPsH>aR~1U7jLbl<-v&yCNEpLjVAEkme3*3lO6i+by4H1|D{bHbTXjq7D=L@X zVC523D4fgY1cAejWLl{rP;Q;#!q8erbod4W=HDqBXxus0r)H-sh%Zv*9chq09eTg| zl(60%%;j@Ck!2|4e!QItfBcbZ*A$tPWAyg@JsXGJ*~ZDhz;34kpKd=;I#4!FZfp$J zY;fSDk-;hi!7t|PY-P&CPh12&pRU@ut)@|tu@3uTNlJZ2RbQ2r#qEw`I*|SX?9B67 z)J?LmCv}vtlUOXRLGJ=Y$#Pb;Ef_aAaQ`#s z?#@TbRtLK`GO_=eQKEJmNRF}S{+k>RtN)(=i+s}v52wi{P9{Lp&=hZ-5+HK}P)f-Y zV~~SgXjD{T%hD|C@Y|@5sDW(6vYD40+YNR9B_fzv492^XKHg+AelDBZ`?z}XfJctE z?2>>-qTtz>KAQR==fErdK}2-}2Q@h6f(W=c!Dsf9I>{>Hd2x>i@5gYKGwQo{3%j&8zi8 z+;57|x4>WUS=T&j-N(});Ote+lq)%T@$dZ?`o^+Qf=j{Y9g+w5`znd4>7Y_DaDL8# zghvf2gnT-FhPMcOP+%pEInkmwPO2BBjaT;X2-kM*fuLT6_6=}$?Q8OQ+Q2@^%uSYc z@xJMMHvVa5&cUMMHp5ujFR`>#a*(Hw3BZUG(Js0&Dr&+MN#%PB)+jeNPpF^C}*tc=|h2)oO zz&oOTxsMz}>%T4Qb3RY!RV%xRLu?y+U6lP8zcz@p`(KL6iWli=&|kmM;gc3U{}z~S zEA&6im5!Qw=c{E}3G!uLhSz*~V69U%Ly(~9zq5nulS=o^W7 -Date: Thu, 15 Nov 2018 13:56:01 -0500 -Subject: [PATCH] Update Breakpad.xib minimum target to OSX10.11 - -Bug: https://bugs.chromium.org/p/google-breakpad/issues/detail?id=778 -Change-Id: I32a36e47d0aab92e5ac40e7fbaa3c5caaaff2318 ---- - -diff --git a/src/client/mac/sender/Breakpad.xib b/src/client/mac/sender/Breakpad.xib -index 7966f89..1ecd27e 100644 ---- a/src/client/mac/sender/Breakpad.xib -+++ b/src/client/mac/sender/Breakpad.xib -@@ -1,1140 +1,224 @@ - -- -- -- 1050 -- 10F569 -- 762 -- 1038.29 -- 461.00 -- -- YES -- -- YES -- -- -- YES -- -- -- -- YES -- -- -- -- YES -- -- -- YES -- -- -- -- YES -- -- Reporter -- -- -- FirstResponder -- -- -- NSApplication -- -- -- 1 -- 2 -- {{72, 251}, {490, 489}} -- 536871936 -- -- NSWindow -- -- {1.79769e+308, 1.79769e+308} -- {72, 5} -- -- -- 264 -- -- YES -- -- -- 272 -- -- YES -- -- -- 256 -- -- YES -- -- -- 290 -- {{17, 36}, {456, 70}} -- -- YES -- -- 67239424 -- 272760832 -- Providing your email address is optional and will allow us contact you in case we need more details. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed arcu urna, pulvinar sit amet, tincidunt ac, fermentum ut, ligula. Quisque mi. Duis lectus. Vestibulum velit. Morbi turpis. Nunc at diam consectetur turpis volutpat tristique. Donec quis diam. Suspendisse scelerisque. -- -- LucidaGrande -- 11 -- 3100 -- -- -- -- 6 -- System -- controlColor -- -- 3 -- MC42NjY2NjY2NjY3AA -- -- -- -- 6 -- System -- controlTextColor -- -- 3 -- MAA -- -- -- -- -- -- -- 290 -- {{87, 9}, {195, 19}} -- -- YES -- -- -1804468671 -- 272761856 -- -- -- optional -- -- YES -- -- 6 -- System -- textBackgroundColor -- -- 3 -- MQA -- -- -- -- 6 -- System -- textColor -- -- -- -- -- -- -- 292 -- {{17, 11}, {65, 14}} -- -- YES -- -- 68288064 -- 71435264 -- EmailLabel: -- -- -- -- -- -- -- -- -- 289 -- {{456, 10}, {16, 17}} -- -- YES -- -- -2080244224 -- 0 -- Privacy Policy -- -- LucidaGrande -- 13 -- 1044 -- -- -- -2040250113 -- 36 -- -- NSImage -- goArrow -- -- -- -- 400 -- 75 -- -- -- -- -- 289 -- {{355, 11}, {100, 14}} -- -- YES -- -- 68288064 -- 4326400 -- PrivacyPolicyLabel -- -- -- -- -- -- -- -- {490, 114} -- -- -- -- {{0, 51}, {490, 114}} -- -- {0, 0} -- -- 67239424 -- 0 -- Title -- -- LucidaGrande -- 11 -- 16 -- -- -- -- 3 -- MCAwLjgwMDAwMDAxAA -- -- -- -- 0 -- 3 -- 0 -- NO -- -- -- -- 289 -- {{330, 12}, {146, 32}} -- -- YES -- -- 67239424 -- 134217728 -- SendReportLabel -- -- -- -2038284033 -- 129 -- -- -- DQ -- 200 -- 25 -- -- -- -- -- 289 -- {{214, 12}, {116, 32}} -- -- YES -- -- 67239424 -- 134217728 -- CancelLabel -- -- -- -2038284033 -- 129 -- -- -- Gw -- 200 -- 25 -- -- -- -- -- 256 -- -- YES -- -- -- 256 -- -- YES -- -- -- 266 -- {{17, 83}, {456, 154}} -- -- YES -- -- 67239424 -- 272760832 -- VGhlIHN5c3RlbSBhbmQgb3RoZXIgYXBwbGljYXRpb25zIGhhdmUgbm90IGJlZW4gYWZmZWN0ZWQuIEEg --cmVwb3J0IGhhcyBiZWVuIGNyZWF0ZWQgdGhhdCB5b3UgY2FuIHNlbmQgdG8gPFJlYWxseSBMb25nIENv --bXBhbnkgTmFtZT4gdG8gaGVscCBpZGVudGlmeSB0aGUgcHJvYmxlbS4gTG9yZW0gaXBzdW0gZG9sb3Ig --c2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4gU2VkIGFyY3UgdXJuYSwgcHVsdmlu --YXIgc2l0IGFtZXQsIHRpbmNpZHVudCBhYywgZmVybWVudHVtIHV0LCBsaWd1bGEuIFF1aXNxdWUgbWku --IER1aXMgbGVjdHVzLiBWZXN0aWJ1bHVtIHZlbGl0LiBNb3JiaSB0dXJwaXMuIE51bmMgYXQgZGlhbSBj --b25zZWN0ZXR1ciB0dXJwaXMgdm9sdXRwYXQgdHJpc3RpcXVlLiBEb25lYyBxdWlzIGRpYW0uIFN1c3Bl --bmRpc3NlIHNjZWxlcmlzcXVlLiBRdWlzcXVlIHB1bHZpbmFyIG1pIGlkIHB1cnVzLiBFdGlhbSB2aXRh --ZSB0dXJwaXMgdml0YWUgbmVxdWUgcG9ydGEgY29uZ3VlLgoKUGxlYXNlIGhlbHAgdXMgZml4IHRoZSBw --cm9ibGVtIGJ5IGRlc2NyaWJpbmcgd2hhdCBoYXBwZW5lZCBiZWZvcmUgdGhlIGNyYXNoLiBMb3JlbSBp --cHN1bSBkb2xvciBzaXQgYW1ldCwgY29uc2VjdGV0dXIgYWRpcGlzY2luZyBlbGl0LiBTZWQgYXJjdSB1 --cm5hLCBwdWx2aW5hciBzaXQgYW1ldCwgdGluY2lkdW50IGFjLCBmZXJtZW50dW0gdXQsIGxpZ3VsYS4g --UXVpc3F1ZSBtaS4gRHVpcyBsZWN0dXMuA -- -- -- -- -- -- -- -- -- 274 -- {{20, 14}, {450, 61}} -- -- YES -- -- 341966337 -- 272760832 -- Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 2 Line 2 Line 2 Line 2 Line 2 Line 2 Line 2 Line 2 Line 2 Line 2 Line 2 Line 2 Line 3 Line 3 Line 3 Line 3 Line 3 Line 3 Line 3 Line 3 Line 3 Line 3 Line 3 Line 3 Line 4 Line 4 Line 4 Line 4 Line 4 Line 4 Line 4 Line 4 Line 4 Line 4 Line 4 Line 4 -- -- -- YES -- -- -- -- -- -- -- 256 -- -- YES -- -- -- 256 -- -- YES -- -- -- 266 -- {{85, 10}, {381, 54}} -- -- YES -- -- 67239424 -- 272629760 -- The application <Really Long App Name Here> has quit unexpectedly. -- -- LucidaGrande-Bold -- 14 -- 16 -- -- -- -- -- -- -- -- -- 268 -- -- YES -- -- YES -- Apple PDF pasteboard type -- Apple PICT pasteboard type -- Apple PNG pasteboard type -- NSFilenamesPboardType -- NeXT Encapsulated PostScript v1.2 pasteboard type -- NeXT TIFF v4.0 pasteboard type -- -- -- {{16, 0}, {64, 64}} -- -- YES -- -- 130560 -- 33554432 -- -- NSImage -- NSApplicationIcon -- -- 0 -- 0 -- 0 -- NO -- -- YES -- -- -- {482, 70} -- -- -- -- {{4, 245}, {482, 70}} -- -- {0, 0} -- -- 67239424 -- 0 -- Title -- -- -- -- 3 -- MCAwLjgwMDAwMDAxAA -- -- -- -- 0 -- 3 -- 0 -- NO -- -- -- {490, 325} -- -- -- -- {{0, 160}, {490, 325}} -- -- {0, 0} -- -- 67239424 -- 0 -- Title -- -- -- -- 3 -- MCAwLjgwMDAwMDAxAA -- -- -- -- 0 -- 3 -- 0 -- NO -- -- -- -- 268 -- {{17, 20}, {163, 14}} -- -- YES -- -- 68288064 -- 272630784 -- xx seconds. -- -- -- -- -- -- -- -- {490, 489} -- -- {{0, 0}, {2560, 1578}} -- {72, 27} -- {1.79769e+308, 1.79769e+308} -- -- -- YES -- -- -- -- -- YES -- -- -- sendReport: -- -- -- -- 45 -- -- -- -- cancel: -- -- -- -- 46 -- -- -- -- showPrivacyPolicy: -- -- -- -- 53 -- -- -- -- value: emailValue -- -- -- -- -- -- value: emailValue -- value -- emailValue -- -- NSNullPlaceholder -- optional -- -- 2 -- -- -- 90 -- -- -- -- initialFirstResponder -- -- -- -- 91 -- -- -- -- value: commentsValue -- -- -- -- -- -- value: commentsValue -- value -- commentsValue -- -- NSNullPlaceholder -- optional comments -- -- 2 -- -- -- 124 -- -- -- -- nextKeyView -- -- -- -- 125 -- -- -- -- nextKeyView -- -- -- -- 126 -- -- -- -- nextKeyView -- -- -- -- 127 -- -- -- -- delegate -- -- -- -- 128 -- -- -- -- alertWindow_ -- -- -- -- 142 -- -- -- -- preEmailBox_ -- -- -- -- 150 -- -- -- -- headerBox_ -- -- -- -- 151 -- -- -- -- emailSectionBox_ -- -- -- -- 152 -- -- -- -- privacyLinkLabel_ -- -- -- -- 153 -- -- -- -- commentMessage_ -- -- -- -- 154 -- -- -- -- dialogTitle_ -- -- -- -- 155 -- -- -- -- emailLabel_ -- -- -- -- 156 -- -- -- -- cancelButton_ -- -- -- -- 158 -- -- -- -- sendButton_ -- -- -- -- 159 -- -- -- -- emailEntryField_ -- -- -- -- 161 -- -- -- -- privacyLinkArrow_ -- -- -- -- 162 -- -- -- -- emailMessage_ -- -- -- -- 163 -- -- -- -- commentsEntryField_ -- -- -- -- 176 -- -- -- -- value: countdownMessage -- -- -- -- -- -- value: countdownMessage -- value -- countdownMessage -- 2 -- -- -- 194 -- -- -- -- countdownLabel_ -- -- -- -- 208 -- -- -- -- -- YES -- -- 0 -- -- -- -- -- -- -2 -- -- -- File's Owner -- -- -- -1 -- -- -- First Responder -- -- -- -3 -- -- -- Application -- -- -- 1 -- -- -- YES -- -- -- -- Window -- -- -- 2 -- -- -- YES -- -- -- -- -- -- -- -- -- -- 12 -- -- -- YES -- -- -- -- -- -- 14 -- -- -- YES -- -- -- -- -- -- 132 -- -- -- YES -- -- -- -- -- -- -- -- -- -- 145 -- -- -- YES -- -- -- -- -- -- -- -- 189 -- -- -- YES -- -- -- -- -- -- 191 -- -- -- Shared User Defaults Controller -- -- -- 210 -- -- -- -- -- 211 -- -- -- -- -- 221 -- -- -- -- -- 58 -- -- -- YES -- -- -- -- -- -- 215 -- -- -- -- -- 18 -- -- -- YES -- -- -- -- -- -- 212 -- -- -- -- -- 20 -- -- -- YES -- -- -- -- -- -- 213 -- -- -- -- -- 48 -- -- -- YES -- -- -- -- -- -- 214 -- -- -- -- -- 66 -- -- -- YES -- -- -- -- -- -- 216 -- -- -- -- -- 8 -- -- -- YES -- -- -- -- -- -- 217 -- -- -- -- -- 116 -- -- -- YES -- -- -- -- -- -- 218 -- -- -- -- -- 147 -- -- -- YES -- -- -- -- -- -- -- 3 -- -- -- YES -- -- -- -- -- -- 219 -- -- -- -- -- 6 -- -- -- YES -- -- -- -- -- -- 220 -- -- -- -- -- -- -- YES -- -- YES -- -3.ImportedFromIB2 -- 1.IBEditorWindowLastContentRect -- 1.IBWindowTemplateEditedContentRect -- 1.ImportedFromIB2 -- 1.windowTemplate.hasMinSize -- 1.windowTemplate.minSize -- 116.CustomClassName -- 116.ImportedFromIB2 -- 12.ImportedFromIB2 -- 132.ImportedFromIB2 -- 14.ImportedFromIB2 -- 145.ImportedFromIB2 -- 147.ImportedFromIB2 -- 18.CustomClassName -- 18.ImportedFromIB2 -- 189.ImportedFromIB2 -- 191.ImportedFromIB2 -- 2.ImportedFromIB2 -- 20.ImportedFromIB2 -- 3.ImportedFromIB2 -- 48.ImportedFromIB2 -- 58.ImportedFromIB2 -- 6.ImportedFromIB2 -- 66.ImportedFromIB2 -- 8.ImportedFromIB2 -- -- -- YES -- -- {{0, 656}, {490, 489}} -- {{0, 656}, {490, 489}} -- -- -- {72, 5} -- LengthLimitingTextField -- -- -- -- -- -- -- LengthLimitingTextField -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- YES -- -- -- YES -- -- -- -- -- YES -- -- -- YES -- -- -- -- 221 -- -- -- -- YES -- -- LengthLimitingTextField -- NSTextField -- -- IBUserSource -- -- -- -- -- Reporter -- NSObject -- -- YES -- -- YES -- cancel: -- sendReport: -- showPrivacyPolicy: -- -- -- YES -- id -- id -- id -- -- -- -- YES -- -- YES -- alertWindow_ -- cancelButton_ -- commentMessage_ -- commentsEntryField_ -- countdownLabel_ -- dialogTitle_ -- emailEntryField_ -- emailLabel_ -- emailMessage_ -- emailSectionBox_ -- headerBox_ -- preEmailBox_ -- privacyLinkArrow_ -- privacyLinkLabel_ -- sendButton_ -- -- -- YES -- NSWindow -- NSButton -- NSTextField -- LengthLimitingTextField -- NSTextField -- NSTextField -- LengthLimitingTextField -- NSTextField -- NSTextField -- NSBox -- NSBox -- NSBox -- NSView -- NSTextField -- NSButton -- -- -- -- IBUserSource -- -- -- -- -- -- 0 -- IBCocoaFramework -- -- com.apple.InterfaceBuilder.CocoaPlugin.macosx -- -- -- -- com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 -- -- -- YES -- ../Breakpad.xcodeproj -- 3 -- -- YES -- -- YES -- NSApplicationIcon -- goArrow -- -- -- YES -- {128, 128} -- {128, 128} -- -- -- -- -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Providing your email address is optional and will allow us contact you in case we need more details. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed arcu urna, pulvinar sit amet, tincidunt ac, fermentum ut, ligula. Quisque mi. Duis lectus. Vestibulum velit. Morbi turpis. Nunc at diam consectetur turpis volutpat tristique. Donec quis diam. Suspendisse scelerisque. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ optional -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ The system and other applications have not been affected. A report has been created that you can send to <Really Long Company Name> to help identify the problem. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed arcu urna, pulvinar sit amet, tincidunt ac, fermentum ut, ligula. Quisque mi. Duis lectus. Vestibulum velit. Morbi turpis. Nunc at diam consectetur turpis volutpat tristique. Donec quis diam. Suspendisse scelerisque. Quisque pulvinar mi id purus. Etiam vitae turpis vitae neque porta congue. -+ -+Please help us fix the problem by describing what happened before the crash. Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed arcu urna, pulvinar sit amet, tincidunt ac, fermentum ut, ligula. Quisque mi. Duis lectus. -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 1 Line 2 Line 2 Line 2 Line 2 Line 2 Line 2 Line 2 Line 2 Line 2 Line 2 Line 2 Line 2 Line 3 Line 3 Line 3 Line 3 Line 3 Line 3 Line 3 Line 3 Line 3 Line 3 Line 3 Line 3 Line 4 Line 4 Line 4 Line 4 Line 4 Line 4 Line 4 Line 4 Line 4 Line 4 Line 4 Line 4 -+ -+ -+ -+ -+ -+ -+ optional comments -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ -+ diff --git a/scripts/prepare_breakpad.bat b/scripts/prepare_breakpad.bat deleted file mode 100644 index fa4fca45..00000000 --- a/scripts/prepare_breakpad.bat +++ /dev/null @@ -1,33 +0,0 @@ -@ECHO OFF -SET ROOT_DIR=%CD% - -powershell -Command "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; wget https://storage.googleapis.com/chrome-infra/depot_tools.zip -OutFile depot_tools.zip " -7z -bd x %ROOT_DIR%\depot_tools.zip -odepot_tools -powershell -Command "depot_tools\update_depot_tools" -SET BUFF_PATH=%PATH% -SET DEPOT_TOOLS=%ROOT_DIR%\depot_tools -set PATH=%DEPOT_TOOLS%;%BUFF_PATH% - -mkdir %ROOT_DIR%\src\breakpad -CD %ROOT_DIR%\src\breakpad -powershell -Command "fetch breakpad" -powershell -Command "gclient sync" -CD %ROOT_DIR%\src\breakpad\src -powershell -Command "git reset --hard 756daa536ad819eff80172aaab262fb71d1e89fd" - -CD %ROOT_DIR%\src\breakpad\src\src\client\windows -DEL %CD%\breakpad_client.gyp -DEL %CD%\breakpad_client.sln -DEL %CD%\common.vcxproj -DEL %CD%\common.vcxproj.filters -DEL %CD%\build_all.vcxproj -COPY %ROOT_DIR%\scripts\breakpad_client.gyp %CD% - -CD %ROOT_DIR%\src\breakpad\src\src -SET GYP_MSVS_VERSION=2017 -powershell -Command "tools\gyp\gyp.bat --no-circular-check client\windows\breakpad_client.gyp -Dwin_release_RuntimeLibrary=2 -Dwin_debug_RuntimeLibrary=2 -Dplatform=%ARCH% -Dconfiguration=release" -devenv client\windows\breakpad_client.sln /upgrade - -set PATH=%BUFF_PATH% -msbuild /m %CD%\client\windows\breakpad_client.sln /p:Configuration=release /p:Platform=%ARCH% || exit /b 1 -CD %ROOT_DIR% diff --git a/scripts/prepare_breakpad_linux.sh b/scripts/prepare_breakpad_linux.sh deleted file mode 100755 index d0dd82b6..00000000 --- a/scripts/prepare_breakpad_linux.sh +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/sh - -set -euo pipefail - -git clone https://github.com/google/breakpad.git -cd breakpad -git clone https://chromium.googlesource.com/linux-syscall-support src/third_party/lss -CFLAGS=-w CXXFLAGS=-w ./configure --disable-tools --prefix=`pwd`/prefix && make -j4 && make install || exit 1 - -export CUSTOM_BREAKPAD_PREFIX="`pwd`/prefix" -cd .. diff --git a/scripts/prepare_breakpad_macos.sh b/scripts/prepare_breakpad_macos.sh deleted file mode 100755 index 9c1e2683..00000000 --- a/scripts/prepare_breakpad_macos.sh +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh - -set -euo pipefail - -SCRIPTPATH=$(realpath "$(dirname "${BASH_SOURCE[0]}")") - -DIR="$SCRIPTPATH/.." -cd "$DIR" -BREAKPAD_FRAMEWORK_DIR="$DIR/breakpad/framework" -BREAKPAD_DUMP_SYMS_DIR="$DIR/breakpad/bin" -git clone https://github.com/google/breakpad.git -mkdir $BREAKPAD_FRAMEWORK_DIR -mkdir $BREAKPAD_DUMP_SYMS_DIR -cd breakpad -git checkout 4d550cceca107f36c4bc1ea1126b7d32cc50f424 -git apply "$SCRIPTPATH/breakpad_macos.patch" -cd src/client/mac/ && xcodebuild -sdk macosx MACOSX_DEPLOYMENT_TARGET=10.14 -cp -R build/Release/Breakpad.framework "$BREAKPAD_FRAMEWORK_DIR" - -cd $DIR/breakpad -cp -R src/. framework/Breakpad.framework/Headers - -export BREAKPAD_FRAMEWORK_DIR=$BREAKPAD_FRAMEWORK_DIR -cd $DIR diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e3c2c97d..f340ee6e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -262,7 +262,6 @@ set(HEADER_FILES common/RunScriptTask.h common/Json.h dialogs/EditMethodDialog.h - common/CrashHandler.h dialogs/TypesInteractionDialog.h widgets/SdbWidget.h plugins/PluginManager.h @@ -393,10 +392,6 @@ if (CUTTER_ENABLE_PYTHON) list(APPEND HEADER_FILES common/QtResImporter.h common/PythonManager.h common/PythonAPI.h) endif() -if(CUTTER_ENABLE_CRASH_REPORTS) - list(APPEND SOURCES common/CrashHandler.cpp) -endif() - if(CUTTER_ENABLE_PYTHON_BINDINGS) set(BINDINGS_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/bindings") set(BINDINGS_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/bindings") @@ -471,19 +466,6 @@ if (TARGET Graphviz::GVC) target_compile_definitions(Cutter PRIVATE CUTTER_ENABLE_GRAPHVIZ) endif() -if(CUTTER_ENABLE_CRASH_REPORTS) - set(THREADS_PREFER_PTHREAD_FLAG ON) - find_package(Threads REQUIRED) - target_link_libraries(Cutter PRIVATE Threads::Threads) - - add_definitions(-DCUTTER_ENABLE_CRASH_REPORTS) - if (NOT WIN32) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g ") - endif() - find_package(Breakpad REQUIRED) - target_link_libraries(Cutter PRIVATE Breakpad::client) -endif() - target_link_libraries(Cutter PUBLIC ${QT_PREFIX}::Core ${QT_PREFIX}::Widgets ${QT_PREFIX}::Gui PRIVATE ${QT_PREFIX}::Svg ${QT_PREFIX}::Network) if (CUTTER_QT6) target_link_libraries(Cutter PUBLIC Qt6::Core5Compat Qt6::SvgWidgets) diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index 9d4d4dff..6f0612b4 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -1,5 +1,4 @@ #include "common/PythonManager.h" -#include "common/CrashHandler.h" #include "CutterApplication.h" #include "plugins/PluginManager.h" #include "CutterConfig.h" diff --git a/src/Main.cpp b/src/Main.cpp index 9c45f5e3..8650b94e 100644 --- a/src/Main.cpp +++ b/src/Main.cpp @@ -3,7 +3,6 @@ #include "core/MainWindow.h" #include "common/UpdateWorker.h" #include "CutterConfig.h" -#include "common/CrashHandler.h" #include "common/SettingsUpgrade.h" #include @@ -55,17 +54,6 @@ static void connectToConsole() int main(int argc, char *argv[]) { -#ifdef CUTTER_ENABLE_CRASH_REPORTS - if (argc >= 3 && QString::fromLocal8Bit(argv[1]) == "--start-crash-handler") { - QApplication app(argc, argv); - QString dumpLocation = QString::fromLocal8Bit(argv[2]); - showCrashDialog(dumpLocation); - return 0; - } - - initCrashHandler(); -#endif - #ifdef Q_OS_WIN connectToConsole(); #endif diff --git a/src/common/CrashHandler.cpp b/src/common/CrashHandler.cpp deleted file mode 100644 index 4c6e56b8..00000000 --- a/src/common/CrashHandler.cpp +++ /dev/null @@ -1,163 +0,0 @@ -#include "CrashHandler.h" -#include "BugReporting.h" - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#if defined(Q_OS_LINUX) -# include "client/linux/handler/exception_handler.h" -#elif defined(Q_OS_WIN32) -# include "client/windows/handler/exception_handler.h" -#elif defined(Q_OS_MACOS) -# include "client/mac/handler/exception_handler.h" -#endif // Q_OS - -static google_breakpad::ExceptionHandler *exceptionHandler = nullptr; - -static void finishCrashHandler() -{ - delete exceptionHandler; -} - -#ifdef Q_OS_WIN32 -// Called if crash dump was successfully created -// Saves path to file -bool callback(const wchar_t *_dump_dir, const wchar_t *_minidump_id, void *context, - EXCEPTION_POINTERS *exinfo, MDRawAssertionInfo *assertion, bool success) -{ - const QDir dir = QString::fromWCharArray(_dump_dir); - const QString id = QString::fromWCharArray(_minidump_id); - QProcess::startDetached(QCoreApplication::applicationFilePath(), - { "--start-crash-handler", dir.filePath(id + ".dmp") }); - _exit(1); - return true; -} -#elif defined(Q_OS_LINUX) -// Called if crash dump was successfully created -// Saves path to file -bool callback(const google_breakpad::MinidumpDescriptor &md, void *context, bool b) -{ - QProcess::startDetached(QCoreApplication::applicationFilePath(), - { "--start-crash-handler", md.path() }); - _exit(1); - return true; -} -#elif defined(Q_OS_MACOS) -// Called if crash dump was successfully created -// Saves path to file -bool callback(const char *dump_dir, const char *minidump_id, void *context, bool succeeded) -{ - const QDir dir = QString::fromUtf8(dump_dir); - const QString id = QString::fromUtf8(minidump_id); - QProcess::startDetached(QCoreApplication::applicationFilePath(), - { "--start-crash-handler", dir.filePath(id + ".dmp") }); - _exit(1); - return true; -} -#endif // Q_OS - -void initCrashHandler() -{ - if (exceptionHandler) { - return; - } - // Here will be placed crash dump at the first place - // and then moved if needed - -#if defined(Q_OS_LINUX) - static std::string tmpLocation = - QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString(); - exceptionHandler = new google_breakpad::ExceptionHandler( - google_breakpad::MinidumpDescriptor(tmpLocation), nullptr, callback, nullptr, true, -1); -#elif defined(Q_OS_MACOS) - static std::string tmpLocation = - QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdString(); - exceptionHandler = new google_breakpad::ExceptionHandler(tmpLocation, nullptr, callback, - nullptr, true, nullptr); -#else - static std::wstring tmpLocation = - QStandardPaths::writableLocation(QStandardPaths::TempLocation).toStdWString(); - exceptionHandler = - new google_breakpad::ExceptionHandler(tmpLocation, nullptr, callback, nullptr, - google_breakpad::ExceptionHandler::HANDLER_ALL); -#endif - atexit(finishCrashHandler); -} - -void showCrashDialog(const QString &dumpFile) -{ - QMessageBox mb; - mb.setWindowTitle(QObject::tr("Crash")); - mb.setText(QObject::tr("Cutter received a signal it can't handle and will close.
" - "Would you like to create a crash dump for a bug report?")); - mb.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - mb.button(QMessageBox::Yes)->setText(QObject::tr("Create a Crash Dump")); - mb.button(QMessageBox::No)->setText(QObject::tr("Quit")); - mb.setDefaultButton(QMessageBox::Yes); - - bool ok = false; - int ret = mb.exec(); - if (ret == QMessageBox::Yes) { - QString dumpSaveFileName; - int placementFailCounter = 0; - do { - placementFailCounter++; - if (placementFailCounter == 4) { - break; - } - dumpSaveFileName = QFileDialog::getSaveFileName( - nullptr, QObject::tr("Choose a directory to save the crash dump in"), - QStandardPaths::writableLocation(QStandardPaths::HomeLocation) - + QDir::separator() + "Cutter_crash_dump_" - + QDate::currentDate().toString("dd.MM.yy") + "_" - + QTime::currentTime().toString("HH.mm.ss") + ".dmp", - QObject::tr("Minidump (*.dmp)")); - - if (dumpSaveFileName.isEmpty()) { - return; - } - if (QFile::rename(dumpFile, dumpSaveFileName)) { - ok = true; - break; - } - QMessageBox::critical(nullptr, QObject::tr("Save Crash Dump"), - QObject::tr("Failed to write to %1.
" - "Please make sure you have access to that directory " - "and try again.") - .arg(QFileInfo(dumpSaveFileName).dir().path())); - } while (true); - - if (ok) { - QMessageBox info; - info.setWindowTitle(QObject::tr("Success")); - info.setText(QObject::tr("Crash dump was successfully created.") - .arg(QFileInfo(dumpSaveFileName).dir().path())); - info.setStandardButtons(QMessageBox::Yes | QMessageBox::No); - - info.button(QMessageBox::Yes)->setText(QObject::tr("Open an Issue")); - info.button(QMessageBox::No)->setText(QObject::tr("Quit")); - info.setDefaultButton(QMessageBox::Yes); - - int ret = info.exec(); - if (ret == QMessageBox::Yes) { - openIssue(); - } - } else { - QMessageBox::critical(nullptr, QObject::tr("Error"), - QObject::tr("Error occurred during crash dump creation.")); - } - } else { - QFile f(dumpFile); - f.remove(); - } -} diff --git a/src/common/CrashHandler.h b/src/common/CrashHandler.h deleted file mode 100644 index 77ef6bf2..00000000 --- a/src/common/CrashHandler.h +++ /dev/null @@ -1,16 +0,0 @@ -#ifndef CRASH_HANDLER_H -#define CRASH_HANDLER_H - -#include - -/** - * @fn void initCrashHandler() - * - * If CUTTER_ENABLE_CRASH_REPORTS is true, initializes - * crash handling and reporting, otherwise does nothing. - */ -void initCrashHandler(); - -void showCrashDialog(const QString &dumpFile); - -#endif // CRASH_HANDLER_H From 3921ba172e2f97e50f3e9e1d4795d91848bb5d28 Mon Sep 17 00:00:00 2001 From: Lovecraft's_Cat <52252627+Lovecrafts-Cat@users.noreply.github.com> Date: Mon, 16 Jan 2023 10:33:08 +0100 Subject: [PATCH 185/240] Added Scoop in the Windows download instructions (#3071) Since Scoop supports this project, it would be sensible to make it explicit for Windows users that it's an available install option. --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5642875b..bdd37783 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,11 @@ Cutter release binaries for all major platforms (Linux, macOS, Windows) can be d - **macOS**: Download the `.dmg` file or use [Homebrew Cask](https://github.com/Homebrew/homebrew-cask): `brew install --cask cutter` -- **Windows**: Download the `.zip` archive or use [Chocolatey](https://chocolatey.org): +- **Windows**: Download the `.zip` archive, or use either [Chocolatey](https://chocolatey.org) or [Scoop](https://scoop.sh/): `choco install cutter` + + `scoop bucket add extras` followed by `scoop install cutter` ### Build from sources From 5144c3f3b50677e9eb1c1a91ea78fbfef67684b9 Mon Sep 17 00:00:00 2001 From: Rohit Bisht <74498290+R-ohit-B-isht@users.noreply.github.com> Date: Thu, 19 Jan 2023 07:19:54 +0530 Subject: [PATCH 186/240] Support graph and disassembly scrolling via PgUp and PgDown --- src/widgets/GraphView.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/widgets/GraphView.cpp b/src/widgets/GraphView.cpp index 95b81348..54b4b438 100644 --- a/src/widgets/GraphView.cpp +++ b/src/widgets/GraphView.cpp @@ -703,7 +703,10 @@ void GraphView::mouseDoubleClickEvent(QMouseEvent *event) void GraphView::keyPressEvent(QKeyEvent *event) { + // for scrolling with arrow keys const int delta = static_cast(30.0 / current_scale); + // for scrolling with pgup/pgdown keys + const int delta2 = static_cast(100.0 / current_scale); int dx = 0, dy = 0; switch (event->key()) { case Qt::Key_Up: @@ -718,6 +721,12 @@ void GraphView::keyPressEvent(QKeyEvent *event) case Qt::Key_Right: dx = delta; break; + case Qt::Key_PageUp: + dy = -delta2; + break; + case Qt::Key_PageDown: + dy = delta2; + break; default: QAbstractScrollArea::keyPressEvent(event); return; From 7f0daf96ddcaf544fa8c2935afc04c2cc172abbf Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Fri, 27 Jan 2023 17:46:12 +0800 Subject: [PATCH 187/240] Update Rizin to the latest `dev` (#3086) --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index d9950f74..b740cba3 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit d9950f74792c1dfb565ac491cc7ef706b80e6044 +Subproject commit b740cba35d43327109ed238fa5562edf01d619c2 From baeffba7d1b2f783c06cc3af51ba7533b3f6df15 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Sun, 29 Jan 2023 16:51:48 +0800 Subject: [PATCH 188/240] Fix #3087 - use new RzStrEnc for RzBinString (#3088) --- src/core/Cutter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index b21a1e03..dc585dd4 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3330,7 +3330,7 @@ QList CutterCore::getAllStrings() StringDescription string; string.string = rz_str_escape_utf8_keep_printable(str->string, &opt); string.vaddr = obj ? rva(obj, str->paddr, str->vaddr, va) : str->paddr; - string.type = str->type; + string.type = rz_str_enc_as_string(str->type); string.size = str->size; string.length = str->length; string.section = section ? section->name : ""; From 9b093d6f4c76fc52035e93eec49bcc8f43ccfc91 Mon Sep 17 00:00:00 2001 From: Khairul Azhar Kasmiran Date: Sun, 5 Feb 2023 22:06:59 +0800 Subject: [PATCH 189/240] Add note on missing `qt5-default` in latest Debian dists (#3106) --- docs/source/building.rst | 3 +++ 1 file changed, 3 insertions(+) diff --git a/docs/source/building.rst b/docs/source/building.rst index 95e9cf74..924e638e 100644 --- a/docs/source/building.rst +++ b/docs/source/building.rst @@ -63,6 +63,9 @@ On Debian-based Linux distributions, all of these essential packages can be inst sudo apt install build-essential cmake meson libzip-dev zlib1g-dev qt5-default libqt5svg5-dev qttools5-dev qttools5-dev-tools +.. note:: + On Debian 11 (bullseye) and higher or Ubuntu 22.04 (Jammy) and higher, replace ``qt5-default`` above with ``qtbase5-dev``. + Depending on your configuration you'll might also need the following: :: From 9bf4dd3be2767b72cbe2f1bc9f58d6323be21fa2 Mon Sep 17 00:00:00 2001 From: Khairul Azhar Kasmiran Date: Wed, 8 Feb 2023 00:48:33 +0800 Subject: [PATCH 190/240] Run always the bundled Rizin's Ninja (#3108) This ensures that the bundled Rizin will always be built when Cutter is, to compile with any changes made to Rizin. --- cmake/BundledRizin.cmake | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index c6982838..85ddd5b5 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -40,6 +40,7 @@ ExternalProject_Add(Rizin-Bundled SOURCE_DIR "${RIZIN_SOURCE_DIR}" CONFIGURE_COMMAND "${MESON}" "" ${MESON_OPTIONS} && "${MESON}" configure ${MESON_OPTIONS} --buildtype "$<$:debug>$<$>:release>" BUILD_COMMAND "${NINJA}" + BUILD_ALWAYS TRUE INSTALL_COMMAND "${NINJA}" install) set(Rizin_INCLUDE_DIRS "${RIZIN_INSTALL_DIR}/include/librz" "${RIZIN_INSTALL_DIR}/include/librz/sdb") From 3e0bc74e77091ee15af5b077ce37a4f33b3685f4 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 8 Feb 2023 01:04:14 +0800 Subject: [PATCH 191/240] Use git branch and revision in version string (#3109) --- CMakeLists.txt | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a62b602a..ce66a7a8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,9 +38,27 @@ set(CUTTER_VERSION_MAJOR 2) set(CUTTER_VERSION_MINOR 1) set(CUTTER_VERSION_PATCH 2) -set(CUTTER_VERSION_FULL "${CUTTER_VERSION_MAJOR}.${CUTTER_VERSION_MINOR}.${CUTTER_VERSION_PATCH}") +set(CUTTER_VERSION "${CUTTER_VERSION_MAJOR}.${CUTTER_VERSION_MINOR}.${CUTTER_VERSION_PATCH}") -project(Cutter VERSION "${CUTTER_VERSION_FULL}") +execute_process(COMMAND git log --pretty=format:'%h' -n 1 + OUTPUT_VARIABLE GIT_REV + ERROR_QUIET) + +# Check whether we got any revision (which isn't +# always the case, e.g. when someone downloaded a zip file +if ("${GIT_REV}" STREQUAL "") + set(CUTTER_VERSION_FULL "${CUTTER_VERSION}") +else() + execute_process( + COMMAND git rev-parse --abbrev-ref HEAD + OUTPUT_VARIABLE GIT_BRANCH) + string(STRIP "${GIT_REV}" GIT_REV) + string(SUBSTRING "${GIT_REV}" 1 7 GIT_REV) + string(STRIP "${GIT_BRANCH}" GIT_BRANCH) + set(CUTTER_VERSION_FULL "${CUTTER_VERSION}-${GIT_BRANCH}-${GIT_REV}") +endif() + +project(Cutter VERSION "${CUTTER_VERSION}") # Enable solution folder support set_property(GLOBAL PROPERTY USE_FOLDERS ON) From bbd4961468f0ca408e5442473f56c75b0fd84781 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Tue, 7 Feb 2023 21:28:40 +0800 Subject: [PATCH 192/240] Use QFontMetrics instead of fontMetrics() --- src/core/MainWindow.cpp | 2 +- src/widgets/ColorThemeListView.cpp | 15 +++++++++------ src/widgets/DisassemblyWidget.cpp | 2 +- src/widgets/SimpleTextGraphView.cpp | 3 ++- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index 46c6fac0..e873b0d7 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -1114,7 +1114,7 @@ void MainWindow::initBackForwardMenu() connect(button, &QWidget::customContextMenuRequested, button, [menu, button](const QPoint &pos) { menu->exec(button->mapToGlobal(pos)); }); - QFontMetrics metrics(fontMetrics()); + QFontMetrics metrics(font()); // Roughly 10-16 lines depending on padding size, no need to calculate more precisely menu->setMaximumHeight(metrics.lineSpacing() * 20); diff --git a/src/widgets/ColorThemeListView.cpp b/src/widgets/ColorThemeListView.cpp index 7d534f57..4f56ba17 100644 --- a/src/widgets/ColorThemeListView.cpp +++ b/src/widgets/ColorThemeListView.cpp @@ -48,8 +48,9 @@ void ColorOptionDelegate::paint(QPainter *painter, const QStyleOptionViewItem &o ColorOption currCO = index.data(Qt::UserRole).value(); + QFontMetrics fm = QFontMetrics(painter->font()); int penWidth = painter->pen().width(); - int fontHeight = painter->fontMetrics().height(); + int fontHeight = fm.height(); QPoint tl = option.rect.topLeft(); QRect optionNameRect; @@ -126,9 +127,9 @@ void ColorOptionDelegate::paint(QPainter *painter, const QStyleOptionViewItem &o painter->setPen(qApp->palette().text().color()); - QString name = - painter->fontMetrics().elidedText(optionInfoMap__[currCO.optionName].displayingtext, - Qt::ElideRight, optionNameRect.width()); + QFontMetrics fm2 = QFontMetrics(painter->font()); + QString name = fm2.elidedText(optionInfoMap__[currCO.optionName].displayingtext, + Qt::ElideRight, optionNameRect.width()); painter->drawText(optionNameRect, name); QPainterPath roundedOptionRect; @@ -155,7 +156,8 @@ void ColorOptionDelegate::paint(QPainter *painter, const QStyleOptionViewItem &o painter->setPen(currCO.color); painter->fillPath(roundedColorRect, currCO.color); - QString desc = painter->fontMetrics().elidedText( + QFontMetrics fm3 = QFontMetrics(painter->font()); + QString desc = fm3.elidedText( currCO.optionName + ": " + optionInfoMap__[currCO.optionName].info, Qt::ElideRight, descTextRect.width()); painter->setPen(qApp->palette().text().color()); @@ -197,7 +199,8 @@ QPixmap ColorOptionDelegate::getPixmapFromSvg(const QString &fileName, const QCo data.replace(QRegularExpression("#[0-9a-fA-F]{6}"), QString("%1").arg(after.name())); QSvgRenderer svgRenderer(data.toUtf8()); - QPixmap pix(QSize(qApp->fontMetrics().height(), qApp->fontMetrics().height())); + QFontMetrics fm = QFontMetrics(qApp->font()); + QPixmap pix(QSize(fm.height(), fm.height())); pix.fill(Qt::transparent); QPainter pixPainter(&pix); diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index be8c9bc9..4c18b57f 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -211,7 +211,7 @@ QString DisassemblyWidget::getWidgetType() QFontMetrics DisassemblyWidget::getFontMetrics() { - return mDisasTextEdit->fontMetrics(); + return QFontMetrics(mDisasTextEdit->font()); } QList DisassemblyWidget::getLines() diff --git a/src/widgets/SimpleTextGraphView.cpp b/src/widgets/SimpleTextGraphView.cpp index feebdd4c..c98c8fcf 100644 --- a/src/widgets/SimpleTextGraphView.cpp +++ b/src/widgets/SimpleTextGraphView.cpp @@ -119,8 +119,9 @@ void SimpleTextGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block, b p.setPen(palette().color(QPalette::WindowText)); // Render node text + QFontMetrics fm = QFontMetrics(p.font()); auto x = block.x + padding / 2; - int y = block.y + padding / 2 + p.fontMetrics().ascent(); + int y = block.y + padding / 2 + fm.ascent(); p.drawText(QPoint(x, y), content.text); } From fdb2f9e545e46afee784e1662c428e86e4b44ef5 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Tue, 7 Feb 2023 21:28:57 +0800 Subject: [PATCH 193/240] Add Qt6 CI job --- .github/workflows/ci.yml | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 38f9b70f..4a2dfe27 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,6 +23,7 @@ jobs: name: [ linux-x86_64, linux-x86_64-system-deps, + linux-x86_64-qt6-system-deps, macos-x86_64, windows-x86_64, tarball @@ -39,6 +40,12 @@ jobs: system-deps: true cc-override: '/usr/bin/gcc-7' cxx-override: '/usr/bin/g++-7' + - name: linux-x86_64-qt6-system-deps # ensure that Cutter can be built at least in basic config on Ubuntu 22.04 using sytem libraries + os: ubuntu-22.04 + python-version: 3.10.x + system-deps: true + cc-override: '/usr/bin/gcc-12' + cxx-override: '/usr/bin/g++-12' - name: linux-x86_64 os: ubuntu-18.04 python-version: 3.7.x @@ -69,16 +76,21 @@ jobs: if: contains(matrix.os, 'ubuntu') run: | sudo apt-get update - sudo apt-get install libgraphviz-dev mesa-common-dev libxkbcommon-x11-dev libclang-8-dev llvm-8 ninja-build - if [[ "${{ matrix.os }}" = "ubuntu-18.04" ]] + sudo apt-get install libgraphviz-dev mesa-common-dev libxkbcommon-x11-dev ninja-build + if [[ "${{ matrix.os }}" = "ubuntu-18.04" || "${{ matrix.os }}" = "ubuntu-20.04" ]] then # install additional packages needed for appimage - sudo apt-get install libxcb1-dev libxkbcommon-dev libxcb-*-dev libegl1 + sudo apt-get install libxcb1-dev libxkbcommon-dev libxcb-*-dev libegl1 libclang-8-dev llvm-8 fi - if [[ "${{ matrix.system-deps }}" = "true" ]] + if [[ "${{ matrix.os }}" = "ubuntu-18.04" && "${{ matrix.system-deps }}" = "true" ]] then sudo apt-get install qt5-default libqt5svg5-dev qttools5-dev qttools5-dev-tools fi + if [[ "${{ matrix.os }}" = "ubuntu-22.04" ]] + then + sudo apt-get install libclang-12-dev llvm-12 qt6-base-dev qt6-tools-dev \ + qt6-tools-dev-tools libqt6svg6-dev libqt6core5compat6-dev libqt6svgwidgets6 qt6-l10n-tools + fi - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} @@ -146,6 +158,14 @@ jobs: -DCMAKE_INSTALL_PREFIX=appdir/usr \ -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON \ .. + elif [[ "${{ matrix.os }}" = "ubuntu-22.04" ]] + then + cmake \ + -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCUTTER_QT6=ON \ + -DCUTTER_USE_BUNDLED_RIZIN=ON \ + .. else cmake \ -G Ninja \ From 957364dedfa83a5bc14389abdb2bbe223d61a023 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Thu, 9 Feb 2023 00:25:55 +0800 Subject: [PATCH 194/240] Update rizin to the latest "stable" (#3107) --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index b740cba3..db6ff0d1 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit b740cba35d43327109ed238fa5562edf01d619c2 +Subproject commit db6ff0d1cd813f452462d8e4b9e0351b6a9cb09e From 6397a2ec6458e051bc4553ca24c02f68cae3c7bc Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Thu, 9 Feb 2023 15:00:37 +0800 Subject: [PATCH 195/240] Update rizin to the latest "stable" (#3112) --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index db6ff0d1..3559b43f 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit db6ff0d1cd813f452462d8e4b9e0351b6a9cb09e +Subproject commit 3559b43f2ffc67e7a5031b7343690c2d596c5afc From d3790af78ee46c9b07ad741d5449cb0d463b1f66 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 15 Feb 2023 02:17:31 +0800 Subject: [PATCH 196/240] Update rizin to the latest "stable" (#3120) --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index 3559b43f..fde96842 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 3559b43f2ffc67e7a5031b7343690c2d596c5afc +Subproject commit fde968429f6ab861278fc756caceb7e5e4e89d81 From 235b75f3ed1e2f1310bef889256188579777eced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Wed, 15 Feb 2023 15:58:45 +0100 Subject: [PATCH 197/240] Update translations (#3122) --- src/translations | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translations b/src/translations index 97429865..e4715bec 160000 --- a/src/translations +++ b/src/translations @@ -1 +1 @@ -Subproject commit 974298653ba71b958e1b6c83f6011f5fefff6236 +Subproject commit e4715bece7d9bff451b188d9bc1dea7eaf50264a From f2e00c59c813170ee8af0ee95fb18bccb0814c33 Mon Sep 17 00:00:00 2001 From: wargio Date: Sat, 18 Feb 2023 21:12:27 +0800 Subject: [PATCH 198/240] Fix #3113 - Wrong usage of rz_cmd_call instead of rz_core_cmd and @! --- src/core/Cutter.cpp | 5 ++--- src/widgets/HexdumpWidget.cpp | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index dc585dd4..8a721109 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -475,8 +475,8 @@ QString CutterCore::cmdRaw(const char *cmd) CORE_LOCK(); rz_cons_push(); - // rz_cmd_call does not return the output of the command - rz_cmd_call(core->rcmd, cmd); + // rz_core_cmd does not return the output of the command + rz_core_cmd(core, cmd, 0); // we grab the output straight from rz_cons res = rz_cons_get_buffer(); @@ -4494,7 +4494,6 @@ QByteArray CutterCore::ioRead(RVA addr, int len) /* Zero-copy */ array.resize(len); if (!rz_io_read_at(core->io, addr, (uint8_t *)array.data(), len)) { - qWarning() << "Can't read data" << addr << len; array.fill(0xff); } diff --git a/src/widgets/HexdumpWidget.cpp b/src/widgets/HexdumpWidget.cpp index e6a088c4..7b5d1acd 100644 --- a/src/widgets/HexdumpWidget.cpp +++ b/src/widgets/HexdumpWidget.cpp @@ -240,7 +240,7 @@ void HexdumpWidget::updateParseWindow(RVA start_address, int size) ui->hexDisasTextEdit->setPlainText( selectedCommand != "" ? Core()->cmdRawAt( - QString("%1 %2").arg(selectedCommand).arg(size), start_address) + QString("%1 @! %2").arg(selectedCommand).arg(size), start_address) : ""); } else { // Fill the information tab hashes and entropy From eb0327ab0c9237d18e036e499d643fe6b65f6345 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Sat, 18 Feb 2023 10:49:32 +0800 Subject: [PATCH 199/240] Update rizin to the latest "stable" --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index fde96842..a7d643ad 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit fde968429f6ab861278fc756caceb7e5e4e89d81 +Subproject commit a7d643ad4bd969f8bc51e90e97c9926330fd53ff From 7057c8606f18f059dfdb3417b216537b182c1fc8 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Sat, 18 Feb 2023 10:50:20 +0800 Subject: [PATCH 200/240] Update Russian and Chinese translations --- src/translations | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translations b/src/translations index e4715bec..41c0c778 160000 --- a/src/translations +++ b/src/translations @@ -1 +1 @@ -Subproject commit e4715bece7d9bff451b188d9bc1dea7eaf50264a +Subproject commit 41c0c778b942577749ea2fed117e48a2cf3892df From 20801f7fe6bb77f72ebca5eae7efd42ea8c9f7f7 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 8 Feb 2023 21:02:00 +0800 Subject: [PATCH 201/240] Enable graphviz for AppImage --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4a2dfe27..757189d2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -145,7 +145,7 @@ jobs: -DPYTHON_INCLUDE_DIR="$CUTTER_DEPS_PYTHON_PREFIX/include/python3.9" \ -DPYTHON_EXECUTABLE="$CUTTER_DEPS_PYTHON_PREFIX/bin/python3" \ -DCUTTER_ENABLE_PYTHON_BINDINGS=ON \ - -DCUTTER_ENABLE_GRAPHVIZ=OFF \ + -DCUTTER_ENABLE_GRAPHVIZ=ON \ -DCUTTER_USE_BUNDLED_RIZIN=ON \ -DCUTTER_APPIMAGE_BUILD=ON \ -DCUTTER_ENABLE_PACKAGING=ON \ From 7a96fad5469d1dd63882923c9b3d398973a9b18c Mon Sep 17 00:00:00 2001 From: wargio Date: Sat, 18 Feb 2023 13:35:49 +0800 Subject: [PATCH 202/240] Fix graph export commands to use c api --- src/core/Cutter.cpp | 65 +++++++++++++++ src/core/Cutter.h | 19 +++++ src/widgets/CallGraph.cpp | 7 +- src/widgets/CutterGraphView.cpp | 114 +++++++++++++------------- src/widgets/CutterGraphView.h | 44 ++++------ src/widgets/DisassemblerGraphView.cpp | 8 +- 6 files changed, 168 insertions(+), 89 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 8a721109..72b8333e 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -4515,3 +4515,68 @@ QStringList CutterCore::getConfigVariableSpaces(const QString &key) rz_list_free(list); return stringList; } + +char *CutterCore::getTextualGraphAt(RzCoreGraphType type, RzCoreGraphFormat format, RVA address) +{ + CORE_LOCK(); + char *string = nullptr; + RzGraph *graph = rz_core_graph(core, type, address); + if (!graph) { + if (address == RVA_INVALID) { + qWarning() << "Cannot get global graph"; + } else { + qWarning() << "Cannot get graph at " << RzAddressString(address); + } + return nullptr; + } + core->graph->is_callgraph = type == RZ_CORE_GRAPH_TYPE_FUNCALL; + + switch (format) { + case RZ_CORE_GRAPH_FORMAT_CMD: { + string = rz_graph_drawable_to_cmd(graph); + break; + } + case RZ_CORE_GRAPH_FORMAT_DOT: { + string = rz_core_graph_to_dot_str(core, graph); + break; + } + case RZ_CORE_GRAPH_FORMAT_JSON: + /* fall-thru */ + case RZ_CORE_GRAPH_FORMAT_JSON_DISASM: { + string = rz_graph_drawable_to_json_str(graph, true); + break; + } + case RZ_CORE_GRAPH_FORMAT_GML: { + string = rz_graph_drawable_to_gml(graph); + break; + } + default: + break; + } + rz_graph_free(graph); + + if (!string) { + qWarning() << "Failed to generate graph"; + } + + return string; +} + +void CutterCore::writeGraphvizGraphToFile(QString path, QString format, RzCoreGraphType type, + RVA address) +{ + TempConfig tempConfig; + tempConfig.set("scr.color", false); + tempConfig.set("graph.gv.format", format); + + CORE_LOCK(); + auto filepath = path.toUtf8(); + + if (!rz_core_graph_write(core, address, type, filepath)) { + if (address == RVA_INVALID) { + qWarning() << "Cannot get global graph"; + } else { + qWarning() << "Cannot get graph at " << RzAddressString(address); + } + } +} \ No newline at end of file diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 7d8aa098..5138807d 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -720,6 +720,25 @@ public: */ bool isWriteModeEnabled(); + /** + * @brief Returns the textual version of global or specific graph. + * @param type Graph type, example RZ_CORE_GRAPH_TYPE_FUNCALL or RZ_CORE_GRAPH_TYPE_IMPORT + * @param format Graph format, example RZ_CORE_GRAPH_FORMAT_DOT or RZ_CORE_GRAPH_FORMAT_GML + * @param address The object address (if global set it to RVA_INVALID) + * @return The textual graph string. + */ + char *getTextualGraphAt(RzCoreGraphType type, RzCoreGraphFormat format, RVA address); + + /** + * @brief Writes a graphviz graph to a file. + * @param path The file output path + * @param format The output format (see graph.gv.format) + * @param type The graph type, example RZ_CORE_GRAPH_TYPE_FUNCALL or + * RZ_CORE_GRAPH_TYPE_IMPORT + * @param address The object address (if global set it to RVA_INVALID) + */ + void writeGraphvizGraphToFile(QString path, QString format, RzCoreGraphType type, RVA address); + signals: void refreshAll(); diff --git a/src/widgets/CallGraph.cpp b/src/widgets/CallGraph.cpp index 001844d0..9836a561 100644 --- a/src/widgets/CallGraph.cpp +++ b/src/widgets/CallGraph.cpp @@ -7,7 +7,9 @@ #include CallGraphWidget::CallGraphWidget(MainWindow *main, bool global) - : MemoryDockWidget(MemoryWidgetType::CallGraph, main), graphView(new CallGraphView(this, main, global)), global(global) + : MemoryDockWidget(MemoryWidgetType::CallGraph, main), + graphView(new CallGraphView(this, main, global)), + global(global) { setObjectName(main ? main->getUniqueObjectName(getWidgetType()) : getWidgetType()); this->setWindowTitle(getWindowTitle()); @@ -53,7 +55,7 @@ void CallGraphView::showExportDialog() } else { defaultName = QString("callgraph_%1").arg(RzAddressString(address)); } - showExportGraphDialog(defaultName, global ? "agC" : "agc", address); + showExportGraphDialog(defaultName, RZ_CORE_GRAPH_TYPE_FUNCALL, global ? RVA_INVALID : address); } void CallGraphView::showAddress(RVA address) @@ -80,7 +82,6 @@ static inline bool isBetween(ut64 a, ut64 x, ut64 b) return (a == UT64_MAX || a <= x) && (b == UT64_MAX || x <= b); } - void CallGraphView::loadCurrentGraph() { blockContent.clear(); diff --git a/src/widgets/CutterGraphView.cpp b/src/widgets/CutterGraphView.cpp index 521bde32..8d89f964 100644 --- a/src/widgets/CutterGraphView.cpp +++ b/src/widgets/CutterGraphView.cpp @@ -152,7 +152,7 @@ void CutterGraphView::zoomReset() void CutterGraphView::showExportDialog() { - showExportGraphDialog("graph", "", RVA_INVALID); + showExportGraphDialog("global_funcall", RZ_CORE_GRAPH_TYPE_FUNCALL, RVA_INVALID); } void CutterGraphView::updateColors() @@ -318,12 +318,12 @@ void CutterGraphView::mouseMoveEvent(QMouseEvent *event) emit graphMoved(); } -void CutterGraphView::exportGraph(QString filePath, GraphExportType type, QString graphCommand, - RVA address) +void CutterGraphView::exportGraph(QString filePath, GraphExportType exportType, + RzCoreGraphType graphType, RVA address) { bool graphTransparent = Config()->getBitmapTransparentState(); double graphScaleFactor = Config()->getBitmapExportScaleFactor(); - switch (type) { + switch (exportType) { case GraphExportType::Png: this->saveAsBitmap(filePath, "png", graphScaleFactor, graphTransparent); break; @@ -335,56 +335,55 @@ void CutterGraphView::exportGraph(QString filePath, GraphExportType type, QStrin break; case GraphExportType::GVDot: - exportRzTextGraph(filePath, graphCommand + "d", address); + exportRzTextGraph(filePath, graphType, RZ_CORE_GRAPH_FORMAT_DOT, address); break; case GraphExportType::RzJson: - exportRzTextGraph(filePath, graphCommand + "j", address); + exportRzTextGraph(filePath, graphType, RZ_CORE_GRAPH_FORMAT_JSON, address); break; case GraphExportType::RzGml: - exportRzTextGraph(filePath, graphCommand + "g", address); - break; - case GraphExportType::RzSDBKeyValue: - exportRzTextGraph(filePath, graphCommand + "k", address); + exportRzTextGraph(filePath, graphType, RZ_CORE_GRAPH_FORMAT_GML, address); break; case GraphExportType::GVJson: - exportRizinGraphvizGraph(filePath, "json", graphCommand, address); + Core()->writeGraphvizGraphToFile(filePath, "json", graphType, address); break; case GraphExportType::GVGif: - exportRizinGraphvizGraph(filePath, "gif", graphCommand, address); + Core()->writeGraphvizGraphToFile(filePath, "gif", graphType, address); break; case GraphExportType::GVPng: - exportRizinGraphvizGraph(filePath, "png", graphCommand, address); + Core()->writeGraphvizGraphToFile(filePath, "png", graphType, address); break; case GraphExportType::GVJpeg: - exportRizinGraphvizGraph(filePath, "jpg", graphCommand, address); + Core()->writeGraphvizGraphToFile(filePath, "jpg", graphType, address); break; case GraphExportType::GVPostScript: - exportRizinGraphvizGraph(filePath, "ps", graphCommand, address); + Core()->writeGraphvizGraphToFile(filePath, "ps", graphType, address); break; case GraphExportType::GVSvg: - exportRizinGraphvizGraph(filePath, "svg", graphCommand, address); + Core()->writeGraphvizGraphToFile(filePath, "svg", graphType, address); + break; + case GraphExportType::GVPdf: + Core()->writeGraphvizGraphToFile(filePath, "pdf", graphType, address); break; } } -void CutterGraphView::exportRizinGraphvizGraph(QString filePath, QString type, QString graphCommand, - RVA address) +void CutterGraphView::exportRzTextGraph(QString filePath, RzCoreGraphType type, + RzCoreGraphFormat format, RVA address) { - TempConfig tempConfig; - tempConfig.set("graph.gv.format", type); - qWarning() << Core()->cmdRawAt(QString("%0w \"%1\"").arg(graphCommand).arg(filePath), address); -} - -void CutterGraphView::exportRzTextGraph(QString filePath, QString graphCommand, RVA address) -{ - QFile file(filePath); - if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) { - qWarning() << "Can't open file"; + char *string = Core()->getTextualGraphAt(type, format, address); + if (!string) { return; } - QTextStream fileOut(&file); - fileOut << Core()->cmdRawAt(QString("%0").arg(graphCommand), address); + + QFile file(filePath); + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { + QTextStream fileOut(&file); + fileOut << string; + } else { + qWarning() << "Can't open or create file: " << filePath; + } + free(string); } bool CutterGraphView::graphIsBitamp(CutterGraphView::GraphExportType type) @@ -403,40 +402,39 @@ bool CutterGraphView::graphIsBitamp(CutterGraphView::GraphExportType type) Q_DECLARE_METATYPE(CutterGraphView::GraphExportType); -void CutterGraphView::showExportGraphDialog(QString defaultName, QString graphCommand, RVA address) +void CutterGraphView::showExportGraphDialog(QString defaultName, RzCoreGraphType type, RVA address) { + qWarning() << defaultName << " - " << type << " addr " << RzAddressString(address); QVector types = { { tr("PNG (*.png)"), "png", QVariant::fromValue(GraphExportType::Png) }, { tr("JPEG (*.jpg)"), "jpg", QVariant::fromValue(GraphExportType::Jpeg) }, { tr("SVG (*.svg)"), "svg", QVariant::fromValue(GraphExportType::Svg) } }; - bool rzGraphExports = !graphCommand.isEmpty(); - if (rzGraphExports) { - types.append({ - { tr("Graphviz dot (*.dot)"), "dot", QVariant::fromValue(GraphExportType::GVDot) }, - { tr("Graph Modelling Language (*.gml)"), "gml", - QVariant::fromValue(GraphExportType::RzGml) }, - { tr("RZ JSON (*.json)"), "json", QVariant::fromValue(GraphExportType::RzJson) }, - { tr("SDB key-value (*.txt)"), "txt", - QVariant::fromValue(GraphExportType::RzSDBKeyValue) }, - }); - bool hasGraphviz = !QStandardPaths::findExecutable("dot").isEmpty() - || !QStandardPaths::findExecutable("xdot").isEmpty(); - if (hasGraphviz) { - types.append({ { tr("Graphviz json (*.json)"), "json", - QVariant::fromValue(GraphExportType::GVJson) }, - { tr("Graphviz gif (*.gif)"), "gif", - QVariant::fromValue(GraphExportType::GVGif) }, - { tr("Graphviz png (*.png)"), "png", - QVariant::fromValue(GraphExportType::GVPng) }, - { tr("Graphviz jpg (*.jpg)"), "jpg", - QVariant::fromValue(GraphExportType::GVJpeg) }, - { tr("Graphviz PostScript (*.ps)"), "ps", - QVariant::fromValue(GraphExportType::GVPostScript) }, - { tr("Graphviz svg (*.svg)"), "svg", - QVariant::fromValue(GraphExportType::GVSvg) } }); - } + types.append({ + { tr("Graphviz dot (*.dot)"), "dot", QVariant::fromValue(GraphExportType::GVDot) }, + { tr("Graph Modelling Language (*.gml)"), "gml", + QVariant::fromValue(GraphExportType::RzGml) }, + { tr("RZ JSON (*.json)"), "json", QVariant::fromValue(GraphExportType::RzJson) }, + }); + + bool hasGraphviz = !QStandardPaths::findExecutable("dot").isEmpty() + || !QStandardPaths::findExecutable("xdot").isEmpty(); + if (hasGraphviz) { + types.append({ { tr("Graphviz json (*.json)"), "json", + QVariant::fromValue(GraphExportType::GVJson) }, + { tr("Graphviz gif (*.gif)"), "gif", + QVariant::fromValue(GraphExportType::GVGif) }, + { tr("Graphviz png (*.png)"), "png", + QVariant::fromValue(GraphExportType::GVPng) }, + { tr("Graphviz jpg (*.jpg)"), "jpg", + QVariant::fromValue(GraphExportType::GVJpeg) }, + { tr("Graphviz PostScript (*.ps)"), "ps", + QVariant::fromValue(GraphExportType::GVPostScript) }, + { tr("Graphviz svg (*.svg)"), "svg", + QVariant::fromValue(GraphExportType::GVSvg) }, + { tr("Graphviz pdf (*.pdf)"), "pdf", + QVariant::fromValue(GraphExportType::GVPdf) } }); } MultitypeFileSaveDialog dialog(this, tr("Export Graph")); @@ -470,5 +468,5 @@ void CutterGraphView::showExportGraphDialog(QString defaultName, QString graphCo } QString filePath = dialog.selectedFiles().first(); - exportGraph(filePath, exportType, graphCommand, address); + exportGraph(filePath, exportType, type, address); } diff --git a/src/widgets/CutterGraphView.h b/src/widgets/CutterGraphView.h index 5a879908..36958743 100644 --- a/src/widgets/CutterGraphView.h +++ b/src/widgets/CutterGraphView.h @@ -32,48 +32,38 @@ public: GVJpeg, GVPostScript, GVSvg, + GVPdf, RzGml, - RzSDBKeyValue, RzJson }; /** * @brief Export graph to a file in the specified format - * @param filePath - * @param type export type, GV* and Rz* types require \p graphCommand - * @param graphCommand rizin graph printing command without type, not required for direct image - * export - * @param address object address for commands like agf + * @param filePath - output file path + * @param exportType - export type, GV* and Rz* types require \p graphCommand + * @param graphType - graph type, example RZ_CORE_GRAPH_TYPE_FUNCALL or + * RZ_CORE_GRAPH_TYPE_IMPORT + * @param address - object address (if global set it to RVA_INVALID) */ - void exportGraph(QString filePath, GraphExportType type, QString graphCommand = "", + void exportGraph(QString filePath, GraphExportType exportType, RzCoreGraphType graphType, RVA address = RVA_INVALID); - /** - * @brief Export image using rizin ag*w command and graphviz. - * Requires graphviz dot executable in the path. - * - * @param filePath output file path - * @param type image format as expected by "e graph.gv.format" - * @param graphCommand rizin command without type, for example agf - * @param address object address if required by command - */ - void exportRizinGraphvizGraph(QString filePath, QString type, QString graphCommand, - RVA address); + /** * @brief Export graph in one of the text formats supported by rizin json, gml, SDB key-value - * @param filePath output file path - * @param graphCommand graph command including the format, example "agfd" or "agfg" - * @param address object address if required by command + * @param filePath - output file path + * @param type - graph type, example RZ_CORE_GRAPH_TYPE_FUNCALL or RZ_CORE_GRAPH_TYPE_IMPORT + * @param format - graph format, example RZ_CORE_GRAPH_FORMAT_DOT or RZ_CORE_GRAPH_FORMAT_GML + * @param address - object address (if global set it to RVA_INVALID) */ - void exportRzTextGraph(QString filePath, QString graphCommand, RVA address); + void exportRzTextGraph(QString filePath, RzCoreGraphType type, RzCoreGraphFormat format, + RVA address); static bool graphIsBitamp(GraphExportType type); /** * @brief Show graph export dialog. * @param defaultName - default file name in the export dialog - * @param graphCommand - rizin graph commmand with graph type and without export type, for - * example afC. Leave empty for non-rizin graphs. In such case only direct image export will be - * available. - * @param address - object address if relevant for \p graphCommand + * @param type - graph type, example RZ_CORE_GRAPH_TYPE_FUNCALL or RZ_CORE_GRAPH_TYPE_IMPORT + * @param address - object address (if global set it to RVA_INVALID) */ - void showExportGraphDialog(QString defaultName, QString graphCommand = "", + void showExportGraphDialog(QString defaultName, RzCoreGraphType type, RVA address = RVA_INVALID); public slots: diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index 008e8fd5..69f87e5b 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -194,6 +194,7 @@ void DisassemblerGraphView::loadCurrentGraph() windowTitle = tr("Graph"); if (fcn && RZ_STR_ISNOTEMPTY(fcn->name)) { + currentFcnAddr = fcn->addr; auto fcnName = fromOwned(rz_str_escape_utf8_for_json(fcn->name, -1)); windowTitle += QString("(%0)").arg(fcnName.get()); } else { @@ -891,6 +892,11 @@ void DisassemblerGraphView::contextMenuEvent(QContextMenuEvent *event) void DisassemblerGraphView::showExportDialog() { + if (currentFcnAddr == RVA_INVALID) { + qWarning() << "Cannot find current function."; + return; + } + QString defaultName = "graph"; if (auto f = Core()->functionIn(currentFcnAddr)) { QString functionName = f->name; @@ -901,7 +907,7 @@ void DisassemblerGraphView::showExportDialog() defaultName = functionName; } } - showExportGraphDialog(defaultName, "agf", currentFcnAddr); + showExportGraphDialog(defaultName, RZ_CORE_GRAPH_TYPE_BLOCK_FUN, currentFcnAddr); } void DisassemblerGraphView::blockDoubleClicked(GraphView::GraphBlock &block, QMouseEvent *event, From b98eb64646f5a570ce9e899b1d779da785f7208b Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Mon, 20 Feb 2023 15:07:27 +0800 Subject: [PATCH 203/240] Remove `pci` hexdump parsing mode --- src/widgets/HexdumpWidget.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/widgets/HexdumpWidget.cpp b/src/widgets/HexdumpWidget.cpp index 7b5d1acd..e772da5f 100644 --- a/src/widgets/HexdumpWidget.cpp +++ b/src/widgets/HexdumpWidget.cpp @@ -144,7 +144,6 @@ void HexdumpWidget::initParsing() ui->parseTypeComboBox->addItem(tr("String"), "pcs"); ui->parseTypeComboBox->addItem(tr("Assembler"), "pca"); ui->parseTypeComboBox->addItem(tr("C bytes"), "pc"); - ui->parseTypeComboBox->addItem(tr("C bytes with instructions"), "pci"); ui->parseTypeComboBox->addItem(tr("C half-words (2 byte)"), "pch"); ui->parseTypeComboBox->addItem(tr("C words (4 byte)"), "pcw"); ui->parseTypeComboBox->addItem(tr("C dwords (8 byte)"), "pcd"); From 54e8e9c40318b7a540fefd9c738e4879342c1d24 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Mon, 20 Feb 2023 17:48:44 +0800 Subject: [PATCH 204/240] Remove LGTM badge --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index bdd37783..d64e349a 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,6 @@ Cutter is a free and open-source reverse engineering platform powered by [rizin] [![Cutter CI](https://github.com/rizinorg/cutter/workflows/Cutter%20CI/badge.svg)](https://github.com/rizinorg/cutter/actions?query=workflow%3A%22Cutter+CI%22) [![Build status](https://ci.appveyor.com/api/projects/status/tn7kttv55b8wf799/branch/dev?svg=true)](https://ci.appveyor.com/project/rizinorg/cutter/branch/dev) -[![Total alerts](https://img.shields.io/lgtm/alerts/g/rizinorg/cutter.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/rizinorg/cutter/alerts/) ![Screenshot](https://raw.githubusercontent.com/rizinorg/cutter/dev/docs/source/images/screenshot.png) From 4701cedfd2fc0cf3229d5f83adbc87aae7f7c906 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Tue, 21 Feb 2023 15:17:01 +0800 Subject: [PATCH 205/240] Get type format from RzBaseType directly --- src/core/Cutter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 72b8333e..dad33c8e 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3850,7 +3850,7 @@ QList CutterCore::getBaseType(RzBaseTypeKind kind, const char * exp.type = type->name; exp.size = rz_type_db_base_get_bitsize(core->analysis->typedb, type); - exp.format = rz_type_format(core->analysis->typedb, type->name); + exp.format = rz_base_type_as_format(core->analysis->typedb, type); exp.category = tr(category); types << exp; } From d39a282ea70164c7afa4d90f466935d81367afd6 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Tue, 21 Feb 2023 21:32:01 +0800 Subject: [PATCH 206/240] Update Rizin to the latest stable --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index a7d643ad..12898a36 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit a7d643ad4bd969f8bc51e90e97c9926330fd53ff +Subproject commit 12898a365e70c22892d78abdd2627e7269533c5f From c68598757de4b2e86fb448c7c082022ffba3b7df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joakim=20Nohlg=C3=A5rd?= Date: Wed, 22 Feb 2023 02:06:32 +0100 Subject: [PATCH 207/240] Fix typo in CMake option names (#3137) --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ce66a7a8..aeb35127 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,8 +25,8 @@ option(CUTTER_ENABLE_PACKAGING "Enable building platform-specific packages for d option(CUTTER_ENABLE_SIGDB "Downloads and installs sigdb (only available when CUTTER_USE_BUNDLED_RIZIN=ON)." OFF) option(CUTTER_PACKAGE_DEPENDENCIES "During install step include the third party dependencies." OFF) option(CUTTER_PACKAGE_RZ_GHIDRA "Compile and install rz-ghidra during install step." OFF) -option(CUTTER_PACKAGE_RZ_LIBSWIFT, "Compile and install rz-libswift demangler during the install step." OFF) -option(CUTTER_PACKAGE_RZ_LIBYARA, "Compile and install rz-libyara during the install step." OFF) +option(CUTTER_PACKAGE_RZ_LIBSWIFT "Compile and install rz-libswift demangler during the install step." OFF) +option(CUTTER_PACKAGE_RZ_LIBYARA "Compile and install rz-libyara during the install step." OFF) option(CUTTER_PACKAGE_JSDEC "Compile and install jsdec during install step." OFF) OPTION(CUTTER_QT6 "Use QT6" OFF) From 68ec5a3da18ee8f281b2926a037ba40ac2d1dab5 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 22 Feb 2023 23:09:24 +0800 Subject: [PATCH 208/240] Fix attaching debugger (#3139) * Fix attaching debugger * Fix deadlock on attach Co-authored-by: wargio --- src/core/Cutter.cpp | 32 +++++++++++++++++++++----------- 1 file changed, 21 insertions(+), 11 deletions(-) diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index dad33c8e..7a18898c 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -2075,16 +2075,23 @@ void CutterCore::attachDebug(int pid) offsetPriorDebugging = getOffset(); } - CORE_LOCK(); - setConfig("cfg.debug", true); - auto uri = rz_str_newf("dbg://%d", pid); - if (currentlyOpenFile.isEmpty()) { - rz_core_file_open_load(core, uri, 0, RZ_PERM_R, false); - } else { - rz_core_file_reopen_remote_debug(core, uri, 0); + if (!asyncTask( + [&](RzCore *core) { + // cannot use setConfig because core is + // already locked, which causes a deadlock + rz_config_set_b(core->config, "cfg.debug", true); + auto uri = rz_str_newf("dbg://%d", pid); + if (currentlyOpenFile.isEmpty()) { + rz_core_file_open_load(core, uri, 0, RZ_PERM_R, false); + } else { + rz_core_file_reopen_remote_debug(core, uri, 0); + } + free(uri); + return nullptr; + }, + debugTask)) { + return; } - free(uri); - emit debugTaskStateChanged(); connect(debugTask.data(), &RizinTask::finished, this, [this, pid]() { @@ -2144,7 +2151,10 @@ void CutterCore::stopDebug() rz_core_analysis_esil_trace_stop(core); currentlyEmulating = false; } else { - rz_core_debug_process_close(core); + // ensure we have opened a file. + if (core->io->desc) { + rz_core_debug_process_close(core); + } currentlyAttachedToPID = -1; } @@ -4579,4 +4589,4 @@ void CutterCore::writeGraphvizGraphToFile(QString path, QString format, RzCoreGr qWarning() << "Cannot get graph at " << RzAddressString(address); } } -} \ No newline at end of file +} From e69a007b8f52eea012417c5bfe576e935bf9044c Mon Sep 17 00:00:00 2001 From: Yappa Date: Sun, 19 Feb 2023 23:10:11 -0800 Subject: [PATCH 209/240] Fix "New Function" Dialog (#3102) --- src/menus/DisassemblyContextMenu.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index ab54328d..918a63fa 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -314,8 +314,7 @@ void DisassemblyContextMenu::addDebugMenu() QVector DisassemblyContextMenu::getThingUsedHere(RVA offset) { RzCoreLocked core(Core()); - auto p = fromOwned( - 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 {}; } @@ -799,7 +798,6 @@ void DisassemblyContextMenu::on_actionAddComment_triggered() void DisassemblyContextMenu::on_actionAnalyzeFunction_triggered() { - bool ok; RVA flagOffset; QString name = Core()->nearestFlag(offset, &flagOffset); if (name.isEmpty() || flagOffset != offset) { @@ -812,12 +810,20 @@ void DisassemblyContextMenu::on_actionAnalyzeFunction_triggered() } // Create dialog - QString functionName = - QInputDialog::getText(this, tr("New function at %1").arg(RzAddressString(offset)), - tr("Function name:"), QLineEdit::Normal, name, &ok); + QInputDialog inputDialog(this->mainWindow); + inputDialog.resize(500, 100); + inputDialog.setWindowTitle(tr("New function at %1").arg(RzAddressString(offset))); + inputDialog.setLabelText(tr("Function name:")); + inputDialog.setTextValue(name); + inputDialog.setWindowFlags(Qt::Window | Qt::WindowMinimizeButtonHint); - // If user accepted - if (ok && !functionName.isEmpty()) { + if (inputDialog.exec() != QDialog::Accepted) { + return; + } + + QString functionName = inputDialog.textValue().trimmed(); + + if (!functionName.isEmpty()) { Core()->createFunctionAt(offset, functionName); } } From 63125b16c73474969fae8df6b7ca7203bc627e40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Sun, 12 Mar 2023 18:54:00 +0100 Subject: [PATCH 210/240] Unify parents of dialogs shown by DisassemblyContextMenu (#3148) Analogous to 2d7fd02a62dd3405d5405a997a8263c6e7706d67, parents of dialogs shown from the DisassemblyContextMenu are consistent now and windowing issues when lauched through shortcuts are fixed. --- src/menus/DecompilerContextMenu.cpp | 2 +- src/menus/DisassemblyContextMenu.cpp | 31 ++++++++++++++++------------ src/menus/DisassemblyContextMenu.h | 5 +++++ 3 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/menus/DecompilerContextMenu.cpp b/src/menus/DecompilerContextMenu.cpp index 2dd6907a..1de95217 100644 --- a/src/menus/DecompilerContextMenu.cpp +++ b/src/menus/DecompilerContextMenu.cpp @@ -387,7 +387,7 @@ void DecompilerContextMenu::actionCopyReferenceAddressTriggered() void DecompilerContextMenu::actionAddCommentTriggered() { - CommentsDialog::addOrEditComment(this->firstOffsetInLine, this); + CommentsDialog::addOrEditComment(this->firstOffsetInLine, parentForDialog()); } void DecompilerContextMenu::actionDeleteCommentTriggered() diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 918a63fa..40b33599 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -161,6 +161,11 @@ DisassemblyContextMenu::DisassemblyContextMenu(QWidget *parent, MainWindow *main DisassemblyContextMenu::~DisassemblyContextMenu() {} +QWidget *DisassemblyContextMenu::parentForDialog() +{ + return parentWidget(); +} + void DisassemblyContextMenu::addSetBaseMenu() { setBaseMenu = addMenu(tr("Set Immediate Base to...")); @@ -690,7 +695,7 @@ void DisassemblyContextMenu::on_actionEditInstruction_triggered() if (!ioModesController.prepareForWriting()) { return; } - EditInstructionDialog e(EDIT_TEXT, this); + EditInstructionDialog e(EDIT_TEXT, parentForDialog()); e.setWindowTitle(tr("Edit Instruction at %1").arg(RzAddressString(offset))); QString oldInstructionOpcode = Core()->getInstructionOpcode(offset); @@ -740,7 +745,7 @@ void DisassemblyContextMenu::on_actionEditBytes_triggered() if (!ioModesController.prepareForWriting()) { return; } - EditInstructionDialog e(EDIT_BYTES, this); + EditInstructionDialog e(EDIT_BYTES, parentForDialog()); e.setWindowTitle(tr("Edit Bytes at %1").arg(RzAddressString(offset))); QString oldBytes = Core()->getInstructionBytes(offset); @@ -774,9 +779,9 @@ void DisassemblyContextMenu::on_actionAdvancedBreakpoint_triggered() { int index = Core()->breakpointIndexAt(offset); if (index >= 0) { - BreakpointsDialog::editBreakpoint(Core()->getBreakpointAt(offset), this); + BreakpointsDialog::editBreakpoint(Core()->getBreakpointAt(offset), parentForDialog()); } else { - BreakpointsDialog::createNewBreakpoint(offset, this); + BreakpointsDialog::createNewBreakpoint(offset, parentForDialog()); } } @@ -793,7 +798,7 @@ void DisassemblyContextMenu::on_actionSetPC_triggered() void DisassemblyContextMenu::on_actionAddComment_triggered() { - CommentsDialog::addOrEditComment(offset, this); + CommentsDialog::addOrEditComment(offset, parentForDialog()); } void DisassemblyContextMenu::on_actionAnalyzeFunction_triggered() @@ -810,7 +815,7 @@ void DisassemblyContextMenu::on_actionAnalyzeFunction_triggered() } // Create dialog - QInputDialog inputDialog(this->mainWindow); + QInputDialog inputDialog(parentForDialog()); inputDialog.resize(500, 100); inputDialog.setWindowTitle(tr("New function at %1").arg(RzAddressString(offset))); inputDialog.setLabelText(tr("Function name:")); @@ -839,12 +844,12 @@ void DisassemblyContextMenu::on_actionRename_triggered() Core()->renameFunction(doRenameInfo.addr, newName); } } else if (doRenameAction == RENAME_FLAG || doRenameAction == RENAME_ADD_FLAG) { - FlagDialog dialog(doRenameInfo.addr, this->mainWindow); + FlagDialog dialog(doRenameInfo.addr, parentForDialog()); ok = dialog.exec(); } else if (doRenameAction == RENAME_LOCAL) { RzAnalysisFunction *fcn = Core()->functionIn(offset); if (fcn) { - EditVariablesDialog dialog(fcn->addr, curHighlightedWord, this->mainWindow); + EditVariablesDialog dialog(fcn->addr, curHighlightedWord, parentForDialog()); if (!dialog.empty()) { // Don't show the dialog if there are no variables ok = dialog.exec(); @@ -873,7 +878,7 @@ void DisassemblyContextMenu::on_actionSetFunctionVarTypes_triggered() return; } - EditVariablesDialog dialog(fcn->addr, curHighlightedWord, this->mainWindow); + EditVariablesDialog dialog(fcn->addr, curHighlightedWord, parentForDialog()); if (dialog.empty()) { // don't show the dialog if there are no variables return; } @@ -898,7 +903,7 @@ void DisassemblyContextMenu::on_actionXRefsForVariables_triggered() void DisassemblyContextMenu::on_actionDisplayOptions_triggered() { - PreferencesDialog dialog(this->window()); + PreferencesDialog dialog(parentForDialog()); dialog.showSection(PreferencesDialog::Section::Disassembly); dialog.exec(); } @@ -920,7 +925,7 @@ void DisassemblyContextMenu::on_actionSetAsStringRemove_triggered() void DisassemblyContextMenu::on_actionSetAsStringAdvanced_triggered() { - EditStringDialog dialog(parentWidget()); + EditStringDialog dialog(parentForDialog()); const int predictedStrSize = Core()->getString(offset).size(); dialog.setStringSizeValue(predictedStrSize); dialog.setStringStartAddress(offset); @@ -970,7 +975,7 @@ void DisassemblyContextMenu::on_actionSetToData_triggered() void DisassemblyContextMenu::on_actionSetToDataEx_triggered() { - SetToDataDialog dialog(offset, this->window()); + SetToDataDialog dialog(offset, parentForDialog()); if (!dialog.exec()) { return; } @@ -1000,7 +1005,7 @@ void DisassemblyContextMenu::on_actionDeleteFunction_triggered() void DisassemblyContextMenu::on_actionEditFunction_triggered() { RzCore *core = Core()->core(); - EditFunctionDialog dialog(mainWindow); + EditFunctionDialog dialog(parentForDialog()); RzAnalysisFunction *fcn = rz_analysis_get_fcn_in(core->analysis, offset, 0); if (fcn) { diff --git a/src/menus/DisassemblyContextMenu.h b/src/menus/DisassemblyContextMenu.h index 158b1ec7..669990a6 100644 --- a/src/menus/DisassemblyContextMenu.h +++ b/src/menus/DisassemblyContextMenu.h @@ -168,6 +168,11 @@ private: QMenu *pluginMenu = nullptr; QAction *pluginActionMenuAction = nullptr; + /** + * \return widget that should be used as parent for presenting dialogs + */ + QWidget *parentForDialog(); + // For creating anonymous entries (that are always visible) QAction *addAnonymousAction(QString name, const char *slot, QKeySequence shortcut); From 1c1355df1f555900d41d361cf8757f5e31f6930e Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Wed, 22 Feb 2023 00:00:00 +0800 Subject: [PATCH 211/240] Bump version to v2.2.0 --- .appveyor.yml | 2 +- CMakeLists.txt | 4 ++-- docs/source/conf.py | 4 ++-- src/re.rizin.cutter.appdata.xml | 1 + 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 375d116e..ef25be60 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,4 +1,4 @@ -version: '2.1.2-git-{build}' +version: '2.2.0-git-{build}' image: 'Visual Studio 2017' clone_depth: 1 diff --git a/CMakeLists.txt b/CMakeLists.txt index aeb35127..8645b267 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,8 +35,8 @@ if(NOT CUTTER_ENABLE_PYTHON) endif() set(CUTTER_VERSION_MAJOR 2) -set(CUTTER_VERSION_MINOR 1) -set(CUTTER_VERSION_PATCH 2) +set(CUTTER_VERSION_MINOR 2) +set(CUTTER_VERSION_PATCH 0) set(CUTTER_VERSION "${CUTTER_VERSION_MAJOR}.${CUTTER_VERSION_MINOR}.${CUTTER_VERSION_PATCH}") diff --git a/docs/source/conf.py b/docs/source/conf.py index 640b7f9b..34af39b1 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -24,9 +24,9 @@ copyright = '2020, The Cutter Developers' author = 'The Cutter Developers' # The short X.Y version -version = '2.1' +version = '2.2' # The full version, including a2lpha/beta/rc tags -release = '2.1.2' +release = '2.2.0' # -- General configuration --------------------------------------------------- diff --git a/src/re.rizin.cutter.appdata.xml b/src/re.rizin.cutter.appdata.xml index e8e0de5e..9ef364ba 100644 --- a/src/re.rizin.cutter.appdata.xml +++ b/src/re.rizin.cutter.appdata.xml @@ -25,6 +25,7 @@ xarkes + From af970e29d798ced25fbaf85a65923220fcaef2f8 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Tue, 7 Mar 2023 10:47:22 +0800 Subject: [PATCH 212/240] Update Rizin to the latest `dev` --- rizin | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rizin b/rizin index 12898a36..3a7d5116 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 12898a365e70c22892d78abdd2627e7269533c5f +Subproject commit 3a7d5116244beb678ad9950bb9dd27d28ed2691f From d3ee310a211b2e04eb3761299ea3fb90a9b7687e Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Mon, 13 Mar 2023 13:39:54 +0800 Subject: [PATCH 213/240] Set Rizin version to 0.6 --- cmake/BundledRizin.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/BundledRizin.cmake b/cmake/BundledRizin.cmake index 85ddd5b5..10816039 100644 --- a/cmake/BundledRizin.cmake +++ b/cmake/BundledRizin.cmake @@ -57,7 +57,7 @@ endif() # TODO: This version number should be fetched automatically # instead of being hardcoded. -set (Rizin_VERSION 0.5) +set (Rizin_VERSION 0.6) set (RZ_LIBS rz_core rz_config rz_cons rz_io rz_util rz_flag rz_asm rz_debug rz_hash rz_bin rz_lang rz_il rz_analysis rz_parse rz_bp rz_egg rz_reg From 1f133741ab0c1475fa48fffc24d1eb4b71dfe532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=A4rkl?= Date: Thu, 30 Mar 2023 19:33:31 +0200 Subject: [PATCH 214/240] Make ClassesWidget a ListDockWidget (#3152) Adds Quick Filter and generic address-based context menu entries to the existing ClassesWidget. The original ClassesWidget.ui is not used anymore as the layout is provided by ListDockWidget and only adjusted. The AddressableItemContextMenu may now also optionally be shown when there no currently selected item by using setShowItemContextMenuWithoutAddress(). This is used e.g. to display the "Create Class" option when nothing is present in the list. Fixes #2237 Co-authored-by: Tristan Crawford --- src/CMakeLists.txt | 1 - src/common/AddressableItemModel.cpp | 8 +- src/menus/AddressableItemContextMenu.cpp | 7 +- src/widgets/AddressableItemList.h | 19 ++- src/widgets/ClassesWidget.cpp | 176 ++++++++++++++--------- src/widgets/ClassesWidget.h | 41 +++--- src/widgets/ClassesWidget.ui | 148 ------------------- src/widgets/ListDockWidget.cpp | 1 - 8 files changed, 160 insertions(+), 241 deletions(-) delete mode 100644 src/widgets/ClassesWidget.ui diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f340ee6e..dd8f524e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -338,7 +338,6 @@ set(UI_FILES dialogs/preferences/InitializationFileEditor.ui widgets/QuickFilterView.ui widgets/DecompilerWidget.ui - widgets/ClassesWidget.ui widgets/VTablesWidget.ui widgets/TypesWidget.ui widgets/SearchWidget.ui diff --git a/src/common/AddressableItemModel.cpp b/src/common/AddressableItemModel.cpp index d36fa594..120b4f38 100644 --- a/src/common/AddressableItemModel.cpp +++ b/src/common/AddressableItemModel.cpp @@ -13,11 +13,17 @@ AddressableFilterProxyModel::AddressableFilterProxyModel(AddressableItemModelI * RVA AddressableFilterProxyModel::address(const QModelIndex &index) const { + if (!addressableSourceModel) { + return RVA_INVALID; + } return addressableSourceModel->address(this->mapToSource(index)); } QString AddressableFilterProxyModel::name(const QModelIndex &index) const { + if (!addressableSourceModel) { + return QString(); + } return addressableSourceModel->name(this->mapToSource(index)); } @@ -28,6 +34,6 @@ void AddressableFilterProxyModel::setSourceModel(QAbstractItemModel *) void AddressableFilterProxyModel::setSourceModel(AddressableItemModelI *sourceModel) { - ParentClass::setSourceModel(sourceModel->asItemModel()); + ParentClass::setSourceModel(sourceModel ? sourceModel->asItemModel() : nullptr); addressableSourceModel = sourceModel; } diff --git a/src/menus/AddressableItemContextMenu.cpp b/src/menus/AddressableItemContextMenu.cpp index 0a82a0f7..8a1d3c7f 100644 --- a/src/menus/AddressableItemContextMenu.cpp +++ b/src/menus/AddressableItemContextMenu.cpp @@ -112,7 +112,8 @@ void AddressableItemContextMenu::aboutToShowSlot() void AddressableItemContextMenu::setHasTarget(bool hasTarget) { this->hasTarget = hasTarget; - for (const auto &action : this->actions()) { - action->setEnabled(hasTarget); - } + actionShowInMenu->setEnabled(hasTarget); + actionCopyAddress->setEnabled(hasTarget); + actionShowXrefs->setEnabled(hasTarget); + actionAddcomment->setEnabled(hasTarget); } diff --git a/src/widgets/AddressableItemList.h b/src/widgets/AddressableItemList.h index 75cd832b..73df3d62 100644 --- a/src/widgets/AddressableItemList.h +++ b/src/widgets/AddressableItemList.h @@ -57,16 +57,30 @@ public: itemContextMenu = menu; } + /** + * If this is set to true, the context menu will also be shown if no item + * is currently selected. + */ + void setShowItemContextMenuWithoutAddress(bool val) { showItemContextMenuWithoutAddress = val; } + protected: virtual void showItemContextMenu(const QPoint &pt) { + if (!itemContextMenu) { + return; + } auto index = this->currentIndex(); - if (index.isValid() && itemContextMenu) { + if (index.isValid()) { auto offset = addressableModel->address(index); auto name = addressableModel->name(index); itemContextMenu->setTarget(offset, name); - itemContextMenu->exec(this->mapToGlobal(pt)); + } else { + if (!showItemContextMenuWithoutAddress) { + return; + } + itemContextMenu->clearTarget(); } + itemContextMenu->exec(this->mapToGlobal(pt)); } virtual void onItemActivated(const QModelIndex &index) @@ -90,6 +104,7 @@ protected: } private: + bool showItemContextMenuWithoutAddress = false; AddressableItemModelI *addressableModel = nullptr; AddressableItemContextMenu *itemContextMenu = nullptr; MainWindow *mainWindow = nullptr; diff --git a/src/widgets/ClassesWidget.cpp b/src/widgets/ClassesWidget.cpp index 42c461ad..5689bc7c 100644 --- a/src/widgets/ClassesWidget.cpp +++ b/src/widgets/ClassesWidget.cpp @@ -1,6 +1,6 @@ #include "ClassesWidget.h" #include "core/MainWindow.h" -#include "ui_ClassesWidget.h" +#include "ui_ListDockWidget.h" #include "common/Helpers.h" #include "common/SvgIconEngine.h" #include "dialogs/EditMethodDialog.h" @@ -9,6 +9,8 @@ #include #include #include +#include +#include QVariant ClassesModel::headerData(int section, Qt::Orientation, int role) const { @@ -33,6 +35,17 @@ QVariant ClassesModel::headerData(int section, Qt::Orientation, int role) const } } +RVA ClassesModel::address(const QModelIndex &index) const +{ + QVariant v = data(index, OffsetRole); + return v.isValid() ? v.toULongLong() : RVA_INVALID; +} + +QString ClassesModel::name(const QModelIndex &index) const +{ + return data(index, NameRole).toString(); +} + BinClassesModel::BinClassesModel(QObject *parent) : ClassesModel(parent) {} void BinClassesModel::setClasses(const QList &classes) @@ -526,12 +539,17 @@ QVariant AnalysisClassesModel::data(const QModelIndex &index, int role) const } ClassesSortFilterProxyModel::ClassesSortFilterProxyModel(QObject *parent) - : QSortFilterProxyModel(parent) + : AddressableFilterProxyModel(nullptr, parent) { + setFilterCaseSensitivity(Qt::CaseInsensitive); + setSortCaseSensitivity(Qt::CaseInsensitive); } bool ClassesSortFilterProxyModel::filterAcceptsRow(int row, const QModelIndex &parent) const { + if (parent.isValid()) + return true; + QModelIndex index = sourceModel()->index(row, 0, parent); return qhelpers::filterStringContains(index.data(ClassesModel::NameRole).toString(), this); } @@ -576,23 +594,63 @@ bool ClassesSortFilterProxyModel::hasChildren(const QModelIndex &parent) const return !parent.isValid() || !parent.parent().isValid(); } -ClassesWidget::ClassesWidget(MainWindow *main) : CutterDockWidget(main), ui(new Ui::ClassesWidget) +ClassesWidget::ClassesWidget(MainWindow *main) + : ListDockWidget(main), + seekToVTableAction(tr("Seek to VTable"), this), + editMethodAction(tr("Edit Method"), this), + addMethodAction(tr("Add Method"), this), + newClassAction(tr("Create new Class"), this), + renameClassAction(tr("Rename Class"), this), + deleteClassAction(tr("Delete Class"), this) { - ui->setupUi(this); + setWindowTitle(tr("Classes")); + setObjectName("ClassesWidget"); - ui->classesTreeView->setIconSize(QSize(10, 10)); + ui->treeView->setIconSize(QSize(10, 10)); proxy_model = new ClassesSortFilterProxyModel(this); - ui->classesTreeView->setModel(proxy_model); - ui->classesTreeView->sortByColumn(ClassesModel::TYPE, Qt::AscendingOrder); - ui->classesTreeView->setContextMenuPolicy(Qt::CustomContextMenu); + setModels(proxy_model); - ui->classSourceCombo->setCurrentIndex(1); + classSourceCombo = new QComboBox(this); + // User an intermediate single-child layout to contain the combo box, otherwise + // when the combo box is inserted directly, the entire vertical layout gets a + // weird horizontal padding on macOS. + QBoxLayout *comboLayout = new QBoxLayout(QBoxLayout::Direction::LeftToRight, nullptr); + comboLayout->addWidget(classSourceCombo); + ui->verticalLayout->insertLayout(ui->verticalLayout->indexOf(ui->quickFilterView), comboLayout); + classSourceCombo->addItem(tr("Binary Info (Fixed)")); + classSourceCombo->addItem(tr("Analysis (Editable)")); + classSourceCombo->setCurrentIndex(1); - connect(ui->classSourceCombo, &QComboBox::currentIndexChanged, this, + connect(classSourceCombo, &QComboBox::currentIndexChanged, this, &ClassesWidget::refreshClasses); - connect(ui->classesTreeView, &QTreeView::customContextMenuRequested, this, - &ClassesWidget::showContextMenu); + + connect(&seekToVTableAction, &QAction::triggered, this, + &ClassesWidget::seekToVTableActionTriggered); + connect(&editMethodAction, &QAction::triggered, this, + &ClassesWidget::editMethodActionTriggered); + connect(&addMethodAction, &QAction::triggered, this, &ClassesWidget::addMethodActionTriggered); + connect(&newClassAction, &QAction::triggered, this, &ClassesWidget::newClassActionTriggered); + connect(&renameClassAction, &QAction::triggered, this, + &ClassesWidget::renameClassActionTriggered); + connect(&deleteClassAction, &QAction::triggered, this, + &ClassesWidget::deleteClassActionTriggered); + + // Build context menu like this: + // class-related actions + // -- classesMethodsSeparator + // method-related actions + // -- separator + // default actions from AddressableItemList + auto contextMenu = ui->treeView->getItemContextMenu(); + contextMenu->insertSeparator(contextMenu->actions().first()); + contextMenu->insertActions(contextMenu->actions().first(), + { &addMethodAction, &editMethodAction, &seekToVTableAction }); + classesMethodsSeparator = contextMenu->insertSeparator(contextMenu->actions().first()); + contextMenu->insertActions(classesMethodsSeparator, + { &newClassAction, &renameClassAction, &deleteClassAction }); + connect(contextMenu, &QMenu::aboutToShow, this, &ClassesWidget::updateActions); + ui->treeView->setShowItemContextMenuWithoutAddress(true); refreshClasses(); } @@ -601,7 +659,7 @@ ClassesWidget::~ClassesWidget() {} ClassesWidget::Source ClassesWidget::getSource() { - switch (ui->classSourceCombo->currentIndex()) { + switch (classSourceCombo->currentIndex()) { case 0: return Source::BIN; default: @@ -614,88 +672,68 @@ void ClassesWidget::refreshClasses() switch (getSource()) { case Source::BIN: if (!bin_model) { - proxy_model->setSourceModel(nullptr); + proxy_model->setSourceModel(static_cast(nullptr)); delete analysis_model; analysis_model = nullptr; bin_model = new BinClassesModel(this); - proxy_model->setSourceModel(bin_model); + proxy_model->setSourceModel(static_cast(bin_model)); } bin_model->setClasses(Core()->getAllClassesFromBin()); break; case Source::ANALYSIS: if (!analysis_model) { - proxy_model->setSourceModel(nullptr); + proxy_model->setSourceModel(static_cast(nullptr)); delete bin_model; bin_model = nullptr; analysis_model = new AnalysisClassesModel(this); - proxy_model->setSourceModel(analysis_model); + proxy_model->setSourceModel(static_cast(analysis_model)); } break; } - qhelpers::adjustColumns(ui->classesTreeView, 3, 0); + qhelpers::adjustColumns(ui->treeView, 3, 0); - ui->classesTreeView->setColumnWidth(0, 200); + ui->treeView->setColumnWidth(0, 200); } -void ClassesWidget::on_classesTreeView_doubleClicked(const QModelIndex &index) +void ClassesWidget::updateActions() { - if (!index.isValid()) - return; + bool isAnalysis = !!analysis_model; + newClassAction.setVisible(isAnalysis); + addMethodAction.setVisible(isAnalysis); - QVariant offsetData = index.data(ClassesModel::OffsetRole); - if (!offsetData.isValid()) { - return; - } - RVA offset = offsetData.value(); - Core()->seekAndShow(offset); -} - -void ClassesWidget::showContextMenu(const QPoint &pt) -{ - if (!analysis_model) { - // no context menu for bin classes - return; + bool rowIsAnalysisClass = false; + bool rowIsAnalysisMethod = false; + QModelIndex index = ui->treeView->selectionModel()->currentIndex(); + if (isAnalysis && index.isValid()) { + auto type = static_cast(index.data(ClassesModel::TypeRole).toInt()); + rowIsAnalysisClass = type == ClassesModel::RowType::Class; + rowIsAnalysisMethod = type == ClassesModel::RowType::Method; } - QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex(); - if (!index.isValid()) { - return; - } - auto type = static_cast(index.data(ClassesModel::TypeRole).toInt()); + renameClassAction.setVisible(rowIsAnalysisClass); + deleteClassAction.setVisible(rowIsAnalysisClass); - QMenu menu(ui->classesTreeView); - - menu.addAction(ui->newClassAction); - - if (type == ClassesModel::RowType::Class) { - menu.addAction(ui->renameClassAction); - menu.addAction(ui->deleteClassAction); - } - - menu.addSeparator(); - - menu.addAction(ui->addMethodAction); - - if (type == ClassesModel::RowType::Method) { - menu.addAction(ui->editMethodAction); + classesMethodsSeparator->setVisible(rowIsAnalysisClass || rowIsAnalysisMethod); + editMethodAction.setVisible(rowIsAnalysisMethod); + bool rowHasVTable = false; + if (rowIsAnalysisMethod) { QString className = index.parent().data(ClassesModel::NameRole).toString(); QString methodName = index.data(ClassesModel::NameRole).toString(); AnalysisMethodDescription desc; if (Core()->getAnalysisMethod(className, methodName, &desc)) { if (desc.vtableOffset >= 0) { - menu.addAction(ui->seekToVTableAction); + rowHasVTable = true; } } } - - menu.exec(ui->classesTreeView->mapToGlobal(pt)); + seekToVTableAction.setVisible(rowHasVTable); } -void ClassesWidget::on_seekToVTableAction_triggered() +void ClassesWidget::seekToVTableActionTriggered() { - QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex(); + QModelIndex index = ui->treeView->selectionModel()->currentIndex(); QString className = index.parent().data(ClassesModel::NameRole).toString(); QList vtables = Core()->getAnalysisClassVTables(className); @@ -714,9 +752,9 @@ void ClassesWidget::on_seekToVTableAction_triggered() Core()->seekAndShow(vtables[0].addr + desc.vtableOffset); } -void ClassesWidget::on_addMethodAction_triggered() +void ClassesWidget::addMethodActionTriggered() { - QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex(); + QModelIndex index = ui->treeView->selectionModel()->currentIndex(); if (!index.isValid()) { return; } @@ -732,9 +770,9 @@ void ClassesWidget::on_addMethodAction_triggered() EditMethodDialog::newMethod(className, QString(), this); } -void ClassesWidget::on_editMethodAction_triggered() +void ClassesWidget::editMethodActionTriggered() { - QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex(); + QModelIndex index = ui->treeView->selectionModel()->currentIndex(); if (!index.isValid() || index.data(ClassesModel::TypeRole).toInt() != static_cast(ClassesModel::RowType::Method)) { @@ -745,7 +783,7 @@ void ClassesWidget::on_editMethodAction_triggered() EditMethodDialog::editMethod(className, methName, this); } -void ClassesWidget::on_newClassAction_triggered() +void ClassesWidget::newClassActionTriggered() { bool ok; QString name = QInputDialog::getText(this, tr("Create new Class"), tr("Class Name:"), @@ -755,9 +793,9 @@ void ClassesWidget::on_newClassAction_triggered() } } -void ClassesWidget::on_deleteClassAction_triggered() +void ClassesWidget::deleteClassActionTriggered() { - QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex(); + QModelIndex index = ui->treeView->selectionModel()->currentIndex(); if (!index.isValid() || index.data(ClassesModel::TypeRole).toInt() != static_cast(ClassesModel::RowType::Class)) { @@ -772,9 +810,9 @@ void ClassesWidget::on_deleteClassAction_triggered() Core()->deleteClass(className); } -void ClassesWidget::on_renameClassAction_triggered() +void ClassesWidget::renameClassActionTriggered() { - QModelIndex index = ui->classesTreeView->selectionModel()->currentIndex(); + QModelIndex index = ui->treeView->selectionModel()->currentIndex(); if (!index.isValid() || index.data(ClassesModel::TypeRole).toInt() != static_cast(ClassesModel::RowType::Class)) { diff --git a/src/widgets/ClassesWidget.h b/src/widgets/ClassesWidget.h index bfe9034e..4b13b740 100644 --- a/src/widgets/ClassesWidget.h +++ b/src/widgets/ClassesWidget.h @@ -5,6 +5,7 @@ #include "core/Cutter.h" #include "CutterDockWidget.h" +#include "widgets/ListDockWidget.h" #include #include @@ -21,7 +22,7 @@ class ClassesWidget; /** * @brief Common abstract base class for Bin and Anal classes models */ -class ClassesModel : public QAbstractItemModel +class ClassesModel : public AddressableItemModel<> { public: enum Columns { NAME = 0, REAL_NAME, TYPE, OFFSET, VTABLE, COUNT }; @@ -69,10 +70,13 @@ public: */ static const int RealNameRole = Qt::UserRole + 4; - explicit ClassesModel(QObject *parent = nullptr) : QAbstractItemModel(parent) {} + explicit ClassesModel(QObject *parent = nullptr) : AddressableItemModel(parent) {} QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + + RVA address(const QModelIndex &index) const override; + QString name(const QModelIndex &index) const override; }; Q_DECLARE_METATYPE(ClassesModel::RowType) @@ -163,7 +167,7 @@ public slots: void classAttrsChanged(const QString &cls); }; -class ClassesSortFilterProxyModel : public QSortFilterProxyModel +class ClassesSortFilterProxyModel : public AddressableFilterProxyModel { Q_OBJECT @@ -176,7 +180,7 @@ protected: bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; }; -class ClassesWidget : public CutterDockWidget +class ClassesWidget : public ListDockWidget { Q_OBJECT @@ -185,29 +189,34 @@ public: ~ClassesWidget(); private slots: - void on_classesTreeView_doubleClicked(const QModelIndex &index); - - void on_seekToVTableAction_triggered(); - void on_addMethodAction_triggered(); - void on_editMethodAction_triggered(); - void on_newClassAction_triggered(); - void on_deleteClassAction_triggered(); - void on_renameClassAction_triggered(); - - void showContextMenu(const QPoint &pt); + void seekToVTableActionTriggered(); + void editMethodActionTriggered(); + void addMethodActionTriggered(); + void newClassActionTriggered(); + void renameClassActionTriggered(); + void deleteClassActionTriggered(); void refreshClasses(); + void updateActions(); private: enum class Source { BIN, ANALYSIS }; Source getSource(); - std::unique_ptr ui; - BinClassesModel *bin_model = nullptr; AnalysisClassesModel *analysis_model = nullptr; ClassesSortFilterProxyModel *proxy_model; + + QComboBox *classSourceCombo; + + QAction seekToVTableAction; + QAction editMethodAction; + QAction addMethodAction; + QAction newClassAction; + QAction renameClassAction; + QAction deleteClassAction; + QAction *classesMethodsSeparator; }; #endif // CLASSESWIDGET_H diff --git a/src/widgets/ClassesWidget.ui b/src/widgets/ClassesWidget.ui deleted file mode 100644 index 42839c0d..00000000 --- a/src/widgets/ClassesWidget.ui +++ /dev/null @@ -1,148 +0,0 @@ - - - ClassesWidget - - - - 0 - 0 - 400 - 300 - - - - Classes - - - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - - - CutterTreeView::item -{ - padding-top: 1px; - padding-bottom: 1px; -} - - - QFrame::NoFrame - - - 0 - - - true - - - false - - - - - - - 10 - - - 0 - - - 0 - - - 0 - - - - - - 0 - 0 - - - - Source: - - - - - - - - 0 - 0 - - - - - Binary Info (Fixed) - - - - - Analysis (Editable) - - - - - - - - - - - Seek to VTable - - - - - Edit Method - - - - - Add Method - - - - - Create new Class - - - - - Rename Class - - - - - Delete Class - - - - - - CutterTreeView - QTreeView -

widgets/CutterTreeView.h
- 1 - - - - - diff --git a/src/widgets/ListDockWidget.cpp b/src/widgets/ListDockWidget.cpp index e8e46ee1..d61a0e1f 100644 --- a/src/widgets/ListDockWidget.cpp +++ b/src/widgets/ListDockWidget.cpp @@ -2,7 +2,6 @@ #include "ui_ListDockWidget.h" #include "core/MainWindow.h" #include "common/Helpers.h" -#include "menus/AddressableItemContextMenu.h" #include #include From fcd504d87f917b93b91ab164b5d53ebb8c2eef49 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Mon, 10 Apr 2023 15:58:34 +0800 Subject: [PATCH 215/240] Update rizin to the latest "dev", translations (#3160) --- rizin | 2 +- src/translations | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rizin b/rizin index 3a7d5116..9ab709bc 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 3a7d5116244beb678ad9950bb9dd27d28ed2691f +Subproject commit 9ab709bc34843f04ffde3b63322c809596123e77 diff --git a/src/translations b/src/translations index 41c0c778..30081249 160000 --- a/src/translations +++ b/src/translations @@ -1 +1 @@ -Subproject commit 41c0c778b942577749ea2fed117e48a2cf3892df +Subproject commit 30081249a58830c3a49838cd4d6d2d6d14a68636 From 3166843dff30f4dd8e77b0836ce481bb54b67e51 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Tue, 11 Apr 2023 11:35:52 +0800 Subject: [PATCH 216/240] Add rz-silhouette to cutter builds (#3161) --- .github/workflows/ci.yml | 3 +++ .woodpecker/macos-arm64.yml | 1 + CMakeLists.txt | 2 ++ dist/CMakeLists.txt | 24 ++++++++++++++++++++++++ dist/bundle_rz_silhouette.ps1 | 17 +++++++++++++++++ scripts/rz-silhouette.sh | 17 +++++++++++++++++ 6 files changed, 64 insertions(+) create mode 100644 dist/bundle_rz_silhouette.ps1 create mode 100755 scripts/rz-silhouette.sh diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 757189d2..983d2b5b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -155,6 +155,7 @@ jobs: -DCUTTER_PACKAGE_JSDEC=ON \ -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \ -DCUTTER_PACKAGE_RZ_LIBYARA=ON \ + -DCUTTER_PACKAGE_RZ_SILHOUETTE=ON \ -DCMAKE_INSTALL_PREFIX=appdir/usr \ -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON \ .. @@ -227,6 +228,7 @@ jobs: -DCUTTER_PACKAGE_JSDEC=ON \ -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON \ -DCUTTER_PACKAGE_RZ_LIBYARA=ON \ + -DCUTTER_PACKAGE_RZ_SILHOUETTE=ON \ -DCPACK_PACKAGE_FILE_NAME="$PACKAGE_NAME" \ -DCPACK_BUNDLE_APPLE_CERT_APP="-" \ .. && \ @@ -266,6 +268,7 @@ jobs: -DCUTTER_PACKAGE_RZ_GHIDRA=ON ^ -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON ^ -DCUTTER_PACKAGE_RZ_LIBYARA=ON ^ + -DCUTTER_PACKAGE_RZ_SILHOUETTE=ON ^ -DCUTTER_PACKAGE_JSDEC=ON ^ -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON ^ -DCMAKE_PREFIX_PATH="%CUTTER_DEPS%\pyside" ^ diff --git a/.woodpecker/macos-arm64.yml b/.woodpecker/macos-arm64.yml index bbff7e68..e2690181 100644 --- a/.woodpecker/macos-arm64.yml +++ b/.woodpecker/macos-arm64.yml @@ -28,6 +28,7 @@ pipeline: -DCUTTER_PACKAGE_JSDEC=ON -DCUTTER_PACKAGE_RZ_LIBSWIFT=ON -DCUTTER_PACKAGE_RZ_LIBYARA=ON + -DCUTTER_PACKAGE_RZ_SILHOUETTE=ON -DCPACK_PACKAGE_FILE_NAME="$$PACKAGE_NAME" -DCPACK_BUNDLE_APPLE_CERT_APP="-" - ninja -C build diff --git a/CMakeLists.txt b/CMakeLists.txt index 8645b267..60cd6c53 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -27,6 +27,7 @@ option(CUTTER_PACKAGE_DEPENDENCIES "During install step include the third party option(CUTTER_PACKAGE_RZ_GHIDRA "Compile and install rz-ghidra during install step." OFF) option(CUTTER_PACKAGE_RZ_LIBSWIFT "Compile and install rz-libswift demangler during the install step." OFF) option(CUTTER_PACKAGE_RZ_LIBYARA "Compile and install rz-libyara during the install step." OFF) +option(CUTTER_PACKAGE_RZ_SILHOUETTE "Compile and install rz-silhouette during the install step." OFF) option(CUTTER_PACKAGE_JSDEC "Compile and install jsdec during install step." OFF) OPTION(CUTTER_QT6 "Use QT6" OFF) @@ -161,6 +162,7 @@ message(STATUS "- Package Dependencies: ${CUTTER_PACKAGE_DEPENDENCIES}") message(STATUS "- Package RzGhidra: ${CUTTER_PACKAGE_RZ_GHIDRA}") message(STATUS "- Package RzLibSwift: ${CUTTER_PACKAGE_RZ_LIBSWIFT}") message(STATUS "- Package RzLibYara: ${CUTTER_PACKAGE_RZ_LIBYARA}") +message(STATUS "- Package RzSilhouette: ${CUTTER_PACKAGE_RZ_SILHOUETTE}") message(STATUS "- Package JSDec: ${CUTTER_PACKAGE_JSDEC}") message(STATUS "- QT6: ${CUTTER_QT6}") message(STATUS "") diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index 956fbd18..822942fd 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -59,6 +59,18 @@ if(WIN32) endif() ") endif() + if (CUTTER_PACKAGE_RZ_SILHOUETTE AND CUTTER_ENABLE_DEPENDENCY_DOWNLOADS) + install(CODE " + set(ENV{RZ_PREFIX} \"\${CMAKE_INSTALL_PREFIX}\") + set(ENV{PATH} \"\${CMAKE_INSTALL_PREFIX};\$ENV{PATH}\") + execute_process(COMMAND powershell \"${CMAKE_CURRENT_SOURCE_DIR}/bundle_rz_silhouette.ps1\" \"\${CMAKE_INSTALL_PREFIX}\" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE SCRIPT_RESULT) + if (SCRIPT_RESULT) + message(FATAL_ERROR \"Failed to package rz-silhouette (returned \${SCRIPT_RESULT})\") + endif() + ") + endif() endif() ################################################ @@ -150,6 +162,18 @@ if(CUTTER_ENABLE_DEPENDENCY_DOWNLOADS AND (NOT WIN32)) endif() ") endif() + if (CUTTER_PACKAGE_RZ_SILHOUETTE) + install(CODE " + execute_process(COMMAND + \"${CMAKE_CURRENT_SOURCE_DIR}/../scripts/rz-silhouette.sh\" + \"\${CMAKE_INSTALL_PREFIX}\" \"${YARA_PLUGIN_OPTIONS}\" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE SCRIPT_RESULT) + if (SCRIPT_RESULT) + message(FATAL_ERROR \"Failed to package rz-silhouette (returned \${SCRIPT_RESULT})\") + endif() + ") + endif() endif() ################################################ diff --git a/dist/bundle_rz_silhouette.ps1 b/dist/bundle_rz_silhouette.ps1 new file mode 100644 index 00000000..4aeeb2b9 --- /dev/null +++ b/dist/bundle_rz_silhouette.ps1 @@ -0,0 +1,17 @@ +$dist = $args[0] +$cmake_opts = $args[1] +$python = Split-Path((Get-Command python.exe).Path) + +if (-not (Test-Path -Path 'rz-silhouette' -PathType Container)) { + git clone https://github.com/rizinorg/rz-silhouette.git --depth 1 rz-silhouette +} +cd rz-silhouette +& meson.exe --buildtype=release --prefix=$dist build +ninja -C build install +$pathdll = "$dist/lib/plugins/rz_silhouette.dll" +if(![System.IO.File]::Exists($pathdll)) { + type build/meson-logs/meson-log.txt + ls "$dist/lib/plugins/" + throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll)) +} +Remove-Item -Recurse -Force $dist/lib/plugins/rz_silhouette.lib diff --git a/scripts/rz-silhouette.sh b/scripts/rz-silhouette.sh new file mode 100755 index 00000000..f2f595e5 --- /dev/null +++ b/scripts/rz-silhouette.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -e + +SCRIPTPATH=$(realpath "$(dirname "${BASH_SOURCE[0]}")") +INSTALL_PREFIX="$1" +EXTRA_CMAKE_OPTS="$2" + +cd "$SCRIPTPATH/.." + +if [[ ! -d rz-silhouette ]]; then + git clone https://github.com/rizinorg/rz-silhouette.git --depth 1 rz-silhouette +fi + +cd rz-silhouette + +meson --buildtype=release --pkg-config-path="$INSTALL_PREFIX/lib/pkgconfig" --prefix="$INSTALL_PREFIX" build +ninja -C build install From b27ee987da92042d3d7e377d19c5aa00705b2924 Mon Sep 17 00:00:00 2001 From: xarkes Date: Thu, 4 May 2023 06:13:57 +0200 Subject: [PATCH 217/240] Update MapFileDialog.cpp (#3165) --- src/dialogs/MapFileDialog.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dialogs/MapFileDialog.cpp b/src/dialogs/MapFileDialog.cpp index dfcd2647..24cbbf7a 100644 --- a/src/dialogs/MapFileDialog.cpp +++ b/src/dialogs/MapFileDialog.cpp @@ -33,7 +33,7 @@ void MapFileDialog::on_buttonBox_accepted() } if (!Core()->mapFile(filePath, mapAddress)) { - QMessageBox::critical(this, tr("Map new file file"), tr("Failed to map a new file")); + QMessageBox::critical(this, tr("Map new file"), tr("Failed to map a new file")); return; } close(); From cf0f7025903064cb18291ca1b89ca7064667f984 Mon Sep 17 00:00:00 2001 From: xarkes Date: Thu, 4 May 2023 06:14:13 +0200 Subject: [PATCH 218/240] Update IOModesController.cpp (#3166) --- src/common/IOModesController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/IOModesController.cpp b/src/common/IOModesController.cpp index 26f0801f..a3ba1edc 100644 --- a/src/common/IOModesController.cpp +++ b/src/common/IOModesController.cpp @@ -91,7 +91,7 @@ bool IOModesController::askCommitUnsavedChanges() // Check if there are uncommitted changes if (!allChangesComitted()) { QMessageBox::StandardButton ret = QMessageBox::question( - NULL, QObject::tr("Uncomitted changes"), + NULL, QObject::tr("Uncommitted changes"), QObject::tr("It seems that you have changes or patches that are not committed to " "the file.\n" "Do you want to commit them now?"), From 68b3cb100414b5e911e755ce737eec0e6209e92f Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Thu, 4 May 2023 15:35:29 +0800 Subject: [PATCH 219/240] Update Japanese, Spanish, Ukranian translations (#3167) --- src/translations | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translations b/src/translations index 30081249..433de885 160000 --- a/src/translations +++ b/src/translations @@ -1 +1 @@ -Subproject commit 30081249a58830c3a49838cd4d6d2d6d14a68636 +Subproject commit 433de8859d1b1853b52e2e82cf75786d09943efb From 8c89dfde8b2f1d78b5c70e0f85f0475943993428 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Sat, 6 May 2023 03:53:40 +0200 Subject: [PATCH 220/240] Show C type definition in tooltip in Types widget (#3169) --- src/widgets/TypesWidget.cpp | 13 +++++++++++++ src/widgets/TypesWidget.h | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/src/widgets/TypesWidget.cpp b/src/widgets/TypesWidget.cpp index 3891314e..c31a50d6 100644 --- a/src/widgets/TypesWidget.cpp +++ b/src/widgets/TypesWidget.cpp @@ -14,6 +14,17 @@ TypesModel::TypesModel(QList *types, QObject *parent) { } +QVariant TypesModel::toolTipValue(const QModelIndex &index) const +{ + TypeDescription t = index.data(TypesModel::TypeDescriptionRole).value(); + + if (t.category == "Primitive") { + return QVariant(); + } + + return Core()->getTypeAsC(t.type).trimmed(); +} + int TypesModel::rowCount(const QModelIndex &) const { return types->count(); @@ -45,6 +56,8 @@ QVariant TypesModel::data(const QModelIndex &index, int role) const default: return QVariant(); } + case Qt::ToolTipRole: + return toolTipValue(index); case TypeDescriptionRole: return QVariant::fromValue(exp); default: diff --git a/src/widgets/TypesWidget.h b/src/widgets/TypesWidget.h index dec3ece5..53037790 100644 --- a/src/widgets/TypesWidget.h +++ b/src/widgets/TypesWidget.h @@ -30,6 +30,11 @@ class TypesModel : public QAbstractListModel private: QList *types; + /** + * @brief Returns a description of the type for the given index + */ + QVariant toolTipValue(const QModelIndex &index) const; + public: enum Columns { TYPE = 0, SIZE, CATEGORY, FORMAT, COUNT }; static const int TypeDescriptionRole = Qt::UserRole; From 882f34048132083fbb3f6b1c0ef6fcf8b58c8a84 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Tue, 9 May 2023 03:48:09 +0200 Subject: [PATCH 221/240] Only jump to reference when double-clicking with left mouse button. (#3174) --- src/widgets/DisassemblyWidget.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index 4c18b57f..6cafb532 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -623,10 +623,12 @@ bool DisassemblyWidget::eventFilter(QObject *obj, QEvent *event) && (obj == mDisasTextEdit || obj == mDisasTextEdit->viewport())) { QMouseEvent *mouseEvent = static_cast(event); - const QTextCursor &cursor = mDisasTextEdit->cursorForPosition(mouseEvent->pos()); - jumpToOffsetUnderCursor(cursor); + if (mouseEvent->button() == Qt::LeftButton) { + const QTextCursor &cursor = mDisasTextEdit->cursorForPosition(mouseEvent->pos()); + jumpToOffsetUnderCursor(cursor); - return true; + return true; + } } else if (Config()->getPreviewValue() && event->type() == QEvent::ToolTip && obj == mDisasTextEdit->viewport()) { From b63ea5b3e4d6829331e5aca2de015cdd4f184379 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Tue, 9 May 2023 03:49:43 +0200 Subject: [PATCH 222/240] Disable expandsOnDoubleClick for Functions widget. (#3172) closes #2788 --- src/widgets/FunctionsWidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/widgets/FunctionsWidget.cpp b/src/widgets/FunctionsWidget.cpp index 61dad3fe..8c439b1d 100644 --- a/src/widgets/FunctionsWidget.cpp +++ b/src/widgets/FunctionsWidget.cpp @@ -508,6 +508,7 @@ FunctionsWidget::FunctionsWidget(MainWindow *main) functionProxyModel = new FunctionSortFilterProxyModel(functionModel, this); setModels(functionProxyModel); ui->treeView->sortByColumn(FunctionModel::NameColumn, Qt::AscendingOrder); + ui->treeView->setExpandsOnDoubleClick(false); titleContextMenu = new QMenu(this); auto viewTypeGroup = new QActionGroup(titleContextMenu); From beec78b4e206b88f7cb8e0b1e0180a5069d6ce54 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Thu, 11 May 2023 03:16:06 +0200 Subject: [PATCH 223/240] Keep topOffset history in disassembly widget. (#3171) This commit adds support for a `topOffset` history (on top of the rizin-managed history), that keeps track of the offset of the top instruction in the disassembly widget. closes #2970 --- src/common/CutterSeekable.cpp | 12 ++++++------ src/common/CutterSeekable.h | 12 ++++++++---- src/core/Cutter.cpp | 8 ++++---- src/core/Cutter.h | 7 +++++-- src/widgets/DisassemblyWidget.cpp | 20 +++++++++++++++++--- src/widgets/DisassemblyWidget.h | 5 ++++- 6 files changed, 44 insertions(+), 20 deletions(-) diff --git a/src/common/CutterSeekable.cpp b/src/common/CutterSeekable.cpp index f8b0805a..12ef7b7b 100644 --- a/src/common/CutterSeekable.cpp +++ b/src/common/CutterSeekable.cpp @@ -13,18 +13,18 @@ CutterSeekable::~CutterSeekable() {} void CutterSeekable::setSynchronization(bool sync) { synchronized = sync; - onCoreSeekChanged(Core()->getOffset()); + onCoreSeekChanged(Core()->getOffset(), CutterCore::SeekHistoryType::New); emit syncChanged(); } -void CutterSeekable::onCoreSeekChanged(RVA addr) +void CutterSeekable::onCoreSeekChanged(RVA addr, CutterCore::SeekHistoryType type) { if (synchronized && widgetOffset != addr) { - updateSeek(addr, true); + updateSeek(addr, type, true); } } -void CutterSeekable::updateSeek(RVA addr, bool localOnly) +void CutterSeekable::updateSeek(RVA addr, CutterCore::SeekHistoryType type, bool localOnly) { previousOffset = widgetOffset; widgetOffset = addr; @@ -32,7 +32,7 @@ void CutterSeekable::updateSeek(RVA addr, bool localOnly) Core()->seek(addr); } - emit seekableSeekChanged(addr); + emit seekableSeekChanged(addr, type); } void CutterSeekable::seekPrev() @@ -40,7 +40,7 @@ void CutterSeekable::seekPrev() if (synchronized) { Core()->seekPrev(); } else { - this->seek(previousOffset); + this->seek(previousOffset, CutterCore::SeekHistoryType::Undo); } } diff --git a/src/common/CutterSeekable.h b/src/common/CutterSeekable.h index b8663cbe..85af3de7 100644 --- a/src/common/CutterSeekable.h +++ b/src/common/CutterSeekable.h @@ -19,8 +19,12 @@ public: * signal will be emitted. * In any case, CutterSeekable::seekableSeekChanged is emitted. * @param addr the location to seek at. + * @param type the type of seek wrt history (Undo, Redo, or New) */ - void seek(RVA addr) { updateSeek(addr, false); } + void seek(RVA addr, CutterCore::SeekHistoryType type = CutterCore::SeekHistoryType::New) + { + updateSeek(addr, type, false); + } /** * @brief setSynchronization sets @@ -67,7 +71,7 @@ private slots: /** * @brief onCoreSeekChanged */ - void onCoreSeekChanged(RVA addr); + void onCoreSeekChanged(RVA addr, CutterCore::SeekHistoryType type); private: /** @@ -91,9 +95,9 @@ private: * @brief internal method for changing the seek * @param localOnly whether the seek should be updated globally if synchronized */ - void updateSeek(RVA addr, bool localOnly); + void updateSeek(RVA addr, CutterCore::SeekHistoryType type, bool localOnly); signals: - void seekableSeekChanged(RVA addr); + void seekableSeekChanged(RVA addr, CutterCore::SeekHistoryType type); void syncChanged(); }; diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index 7a18898c..ebbd2142 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -1002,19 +1002,19 @@ void CutterCore::seekPrev() { CORE_LOCK(); rz_core_seek_undo(core); - updateSeek(); + updateSeek(SeekHistoryType::Undo); } void CutterCore::seekNext() { CORE_LOCK(); rz_core_seek_redo(core); - updateSeek(); + updateSeek(SeekHistoryType::Redo); } -void CutterCore::updateSeek() +void CutterCore::updateSeek(SeekHistoryType type) { - emit seekChanged(getOffset()); + emit seekChanged(getOffset(), type); } RVA CutterCore::prevOpAddr(RVA startAddr, int count) diff --git a/src/core/Cutter.h b/src/core/Cutter.h index 5138807d..dd9e67c8 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -172,6 +172,8 @@ public: return returner; } + enum class SeekHistoryType { New, Undo, Redo }; + CutterJson cmdj(const char *str); CutterJson cmdj(const QString &str) { return cmdj(str.toUtf8().constData()); } QString cmdTask(const QString &str); @@ -324,7 +326,7 @@ public: void seekSilent(QString thing) { seekSilent(math(thing)); } void seekPrev(); void seekNext(); - void updateSeek(); + void updateSeek(SeekHistoryType type = SeekHistoryType::New); /** * @brief Raise a memory widget showing current offset, prefer last active * memory widget. @@ -794,8 +796,9 @@ signals: /** * @brief seekChanged is emitted each time Rizin's seek value is modified * @param offset + * @param historyType */ - void seekChanged(RVA offset); + void seekChanged(RVA offset, SeekHistoryType type = SeekHistoryType::New); void toggleDebugView(); diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index 6cafb532..4d3dbe2b 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -327,6 +327,7 @@ void DisassemblyWidget::scrollInstructions(int count) } refreshDisasm(offset); + topOffsetHistory[topOffsetHistoryPos] = offset; } bool DisassemblyWidget::updateMaxLines() @@ -660,19 +661,32 @@ QString DisassemblyWidget::getWindowTitle() const return tr("Disassembly"); } -void DisassemblyWidget::on_seekChanged(RVA offset) +void DisassemblyWidget::on_seekChanged(RVA offset, CutterCore::SeekHistoryType type) { + if (type == CutterCore::SeekHistoryType::New) { + // Erase previous history past this point. + topOffsetHistory.erase(topOffsetHistory.begin() + topOffsetHistoryPos + 1, + topOffsetHistory.end()); + topOffsetHistory.push_back(offset); + topOffsetHistoryPos = topOffsetHistory.size() - 1; + } else if (type == CutterCore::SeekHistoryType::Undo) { + --topOffsetHistoryPos; + } else if (type == CutterCore::SeekHistoryType::Redo) { + ++topOffsetHistoryPos; + } if (!seekFromCursor) { cursorLineOffset = 0; cursorCharOffset = 0; } - if (topOffset != RVA_INVALID && offset >= topOffset && offset <= bottomOffset) { + if (topOffset != RVA_INVALID && offset >= topOffset && offset <= bottomOffset + && type == CutterCore::SeekHistoryType::New) { // if the line with the seek offset is currently visible, just move the cursor there updateCursorPosition(); + topOffsetHistory[topOffsetHistoryPos] = topOffset; } else { // otherwise scroll there - refreshDisasm(offset); + refreshDisasm(topOffsetHistory[topOffsetHistoryPos]); } mCtxMenu->setOffset(offset); } diff --git a/src/widgets/DisassemblyWidget.h b/src/widgets/DisassemblyWidget.h index 1ab16216..05a47579 100644 --- a/src/widgets/DisassemblyWidget.h +++ b/src/widgets/DisassemblyWidget.h @@ -51,7 +51,7 @@ public slots: QList getLines(); protected slots: - void on_seekChanged(RVA offset); + void on_seekChanged(RVA offset, CutterCore::SeekHistoryType type); void refreshIfInRange(RVA offset); void refreshDisasm(RVA offset = RVA_INVALID); @@ -87,6 +87,9 @@ private: void keyPressEvent(QKeyEvent *event) override; QString getWindowTitle() const override; + int topOffsetHistoryPos = 0; + QList topOffsetHistory; + QList breakpoints; void setupFonts(); From 5a12f7c6267afbdf5a6e0cdd4a0a5b2d78fc2807 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Thu, 11 May 2023 13:44:33 +0800 Subject: [PATCH 224/240] Fix 'Rizin Graph' widget (#3179) --- src/widgets/RizinGraphWidget.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/widgets/RizinGraphWidget.cpp b/src/widgets/RizinGraphWidget.cpp index 346cf012..b228e4a4 100644 --- a/src/widgets/RizinGraphWidget.cpp +++ b/src/widgets/RizinGraphWidget.cpp @@ -96,7 +96,7 @@ void GenericRizinGraphView::loadCurrentGraph() return; } - CutterJson functionsDoc = Core()->cmdj(QString("%1j").arg(graphCommand)); + CutterJson functionsDoc = Core()->cmdj(QString("%1 json").arg(graphCommand)); auto nodes = functionsDoc["nodes"]; for (CutterJson block : nodes) { From 3e402c225e4dbf7ea6521930eb6fc571de3c0c1c Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Fri, 12 May 2023 14:48:27 +0800 Subject: [PATCH 225/240] Update Hindi, French, Russian translations (#3182) --- src/translations | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/translations b/src/translations index 433de885..e8fc5ca1 160000 --- a/src/translations +++ b/src/translations @@ -1 +1 @@ -Subproject commit 433de8859d1b1853b52e2e82cf75786d09943efb +Subproject commit e8fc5ca1acd70fd82a2ac9ac02b0261e57703250 From f1a421c9f696d33ef1b7aa6fe84a271a05556af8 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Fri, 12 May 2023 13:52:41 +0200 Subject: [PATCH 226/240] Fix disassembly scroll history. (#3183) Avoid calling `erase()` when `topOffsetHistoryPos + 1 >= `topOffsetHistory.size()`. closes #3181 --- src/widgets/DisassemblyWidget.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index 4d3dbe2b..ebbbfa0d 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -665,8 +665,10 @@ void DisassemblyWidget::on_seekChanged(RVA offset, CutterCore::SeekHistoryType t { if (type == CutterCore::SeekHistoryType::New) { // Erase previous history past this point. - topOffsetHistory.erase(topOffsetHistory.begin() + topOffsetHistoryPos + 1, - topOffsetHistory.end()); + if (topOffsetHistory.size() > topOffsetHistoryPos + 1) { + topOffsetHistory.erase(topOffsetHistory.begin() + topOffsetHistoryPos + 1, + topOffsetHistory.end()); + } topOffsetHistory.push_back(offset); topOffsetHistoryPos = topOffsetHistory.size() - 1; } else if (type == CutterCore::SeekHistoryType::Undo) { From a6a766785226c1330e87ac4eebb6bf945c535083 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Fri, 12 May 2023 23:57:35 +0200 Subject: [PATCH 227/240] Keep scroll history in decompiler widget. (#3177) * Keep scroll history in decompiler widget. This commit adds a `scrollHistory` on top of the rizin-managed history, that keeps track of the scroll position within decompiled functions. * Fix clearing history upon init. --- src/widgets/DecompilerWidget.cpp | 35 +++++++++++++++++++------------- src/widgets/DecompilerWidget.h | 6 +++--- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/src/widgets/DecompilerWidget.cpp b/src/widgets/DecompilerWidget.cpp index 9414f118..60586192 100644 --- a/src/widgets/DecompilerWidget.cpp +++ b/src/widgets/DecompilerWidget.cpp @@ -26,8 +26,7 @@ DecompilerWidget::DecompilerWidget(MainWindow *main) ui(new Ui::DecompilerWidget), decompilerBusy(false), seekFromCursor(false), - scrollerHorizontal(0), - scrollerVertical(0), + historyPos(0), previousFunctionAddr(RVA_INVALID), decompiledFunctionAddr(RVA_INVALID), code(Decompiler::makeWarning(tr("Choose an offset and refresh to get decompiled code")), @@ -311,13 +310,6 @@ QTextCursor DecompilerWidget::getCursorForAddress(RVA addr) void DecompilerWidget::decompilationFinished(RzAnnotatedCode *codeDecompiled) { - bool isDisplayReset = false; - if (previousFunctionAddr == decompiledFunctionAddr) { - scrollerHorizontal = ui->textEdit->horizontalScrollBar()->sliderPosition(); - scrollerVertical = ui->textEdit->verticalScrollBar()->sliderPosition(); - isDisplayReset = true; - } - ui->progressLabel->setVisible(false); ui->decompilerComboBox->setEnabled(decompilerSelectionEnabled); @@ -354,10 +346,8 @@ void DecompilerWidget::decompilationFinished(RzAnnotatedCode *codeDecompiled) } } - if (isDisplayReset) { - ui->textEdit->horizontalScrollBar()->setSliderPosition(scrollerHorizontal); - ui->textEdit->verticalScrollBar()->setSliderPosition(scrollerVertical); - } + ui->textEdit->horizontalScrollBar()->setSliderPosition(scrollHistory[historyPos].first); + ui->textEdit->verticalScrollBar()->setSliderPosition(scrollHistory[historyPos].second); } void DecompilerWidget::setAnnotationsAtCursor(size_t pos) @@ -416,11 +406,28 @@ void DecompilerWidget::cursorPositionChanged() updateSelection(); } -void DecompilerWidget::seekChanged() +void DecompilerWidget::seekChanged(RVA /* addr */, CutterCore::SeekHistoryType type) { if (seekFromCursor) { return; } + + if (!scrollHistory.empty()) { // History is empty upon init. + scrollHistory[historyPos] = { ui->textEdit->horizontalScrollBar()->sliderPosition(), + ui->textEdit->verticalScrollBar()->sliderPosition() }; + } + if (type == CutterCore::SeekHistoryType::New) { + // Erase previous history past this point. + if (scrollHistory.size() > historyPos + 1) { + scrollHistory.erase(scrollHistory.begin() + historyPos + 1, scrollHistory.end()); + } + scrollHistory.push_back({ 0, 0 }); + historyPos = scrollHistory.size() - 1; + } else if (type == CutterCore::SeekHistoryType::Undo) { + --historyPos; + } else if (type == CutterCore::SeekHistoryType::Redo) { + ++historyPos; + } RVA fcnAddr = Core()->getFunctionStart(seekable->getOffset()); if (fcnAddr == RVA_INVALID || fcnAddr != decompiledFunctionAddr) { doRefresh(); diff --git a/src/widgets/DecompilerWidget.h b/src/widgets/DecompilerWidget.h index 015525af..ed5c7f0c 100644 --- a/src/widgets/DecompilerWidget.h +++ b/src/widgets/DecompilerWidget.h @@ -53,7 +53,7 @@ private slots: * - Seek changed to an offset contained in the decompiled function. * - Auto-refresh is disabled. */ - void seekChanged(); + void seekChanged(RVA /* addr */, CutterCore::SeekHistoryType type); void decompilationFinished(RzAnnotatedCode *code); private: @@ -72,8 +72,8 @@ private: bool decompilerBusy; bool seekFromCursor; - int scrollerHorizontal; - int scrollerVertical; + int historyPos; + QVector> scrollHistory; RVA previousFunctionAddr; RVA decompiledFunctionAddr; std::unique_ptr code; From 3ccccae291f98b5947bae2829b5fbed48db17140 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Sat, 13 May 2023 10:22:05 +0800 Subject: [PATCH 228/240] Fix broken English in UI (#3184) --- src/common/Configuration.cpp | 4 ++-- src/common/DisassemblyPreview.cpp | 7 ------- src/dialogs/InitialOptionsDialog.ui | 2 +- src/dialogs/NewFileDialog.cpp | 2 +- src/dialogs/preferences/AsmOptionsWidget.ui | 4 ++-- src/menus/DisassemblyContextMenu.cpp | 2 +- src/widgets/ColorThemeListView.cpp | 3 +-- src/widgets/HexWidget.cpp | 4 ++-- 8 files changed, 10 insertions(+), 18 deletions(-) diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index 7fc76715..12af053f 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -143,8 +143,8 @@ Configuration::Configuration() : QObject(), nativePalette(qApp->palette()) mPtr = this; if (!s.isWritable()) { QMessageBox::critical( - nullptr, tr("Critical!"), - tr("!!! Settings are not writable! Make sure you have a write access to \"%1\"") + nullptr, tr("Critical Error!"), + tr("Settings are not writable! Make sure you have a write access to \"%1\".") .arg(s.fileName())); } #ifdef CUTTER_ENABLE_KSYNTAXHIGHLIGHTING diff --git a/src/common/DisassemblyPreview.cpp b/src/common/DisassemblyPreview.cpp index e80e6eaa..4861c769 100644 --- a/src/common/DisassemblyPreview.cpp +++ b/src/common/DisassemblyPreview.cpp @@ -44,13 +44,6 @@ bool DisassemblyPreview::showDisasPreview(QWidget *parent, const QPoint &pointOf } RVA offsetTo = refs.at(0).to; // This is the offset we want to preview - - if (Q_UNLIKELY(offsetFrom != refs.at(0).from)) { - qWarning() << QObject::tr("offsetFrom (%1) differs from refs.at(0).from (%(2))") - .arg(offsetFrom) - .arg(refs.at(0).from); - } - /* * Only if the offset we point *to* is different from the one the cursor is currently * on *and* the former is a valid offset, we are allowed to get a preview of offsetTo diff --git a/src/dialogs/InitialOptionsDialog.ui b/src/dialogs/InitialOptionsDialog.ui index e3db9f83..38316893 100644 --- a/src/dialogs/InitialOptionsDialog.ui +++ b/src/dialogs/InitialOptionsDialog.ui @@ -323,7 +323,7 @@ - Auto Exp + Experimental Qt::AlignCenter diff --git a/src/dialogs/NewFileDialog.cpp b/src/dialogs/NewFileDialog.cpp index cde5fc85..58d0d391 100644 --- a/src/dialogs/NewFileDialog.cpp +++ b/src/dialogs/NewFileDialog.cpp @@ -287,7 +287,7 @@ void NewFileDialog::fillIOPluginsList() { ui->ioPlugin->clear(); ui->ioPlugin->addItem("file://"); - ui->ioPlugin->setItemData(0, tr("Open a file with no extra treatment."), Qt::ToolTipRole); + ui->ioPlugin->setItemData(0, tr("Open a file without additional options/settings."), Qt::ToolTipRole); int index = 1; QList ioPlugins = Core()->getRIOPluginDescriptions(); diff --git a/src/dialogs/preferences/AsmOptionsWidget.ui b/src/dialogs/preferences/AsmOptionsWidget.ui index e96421a4..f3f14952 100644 --- a/src/dialogs/preferences/AsmOptionsWidget.ui +++ b/src/dialogs/preferences/AsmOptionsWidget.ui @@ -142,7 +142,7 @@ - Tabs before assembly (asm.tabs.off): + The number of tabulate spaces after the offset (asm.tabs.off): Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse @@ -479,7 +479,7 @@ - Substitute variables (asm.sub.var) + Substitute variables in disassembly (asm.sub.var) diff --git a/src/menus/DisassemblyContextMenu.cpp b/src/menus/DisassemblyContextMenu.cpp index 40b33599..300283cc 100644 --- a/src/menus/DisassemblyContextMenu.cpp +++ b/src/menus/DisassemblyContextMenu.cpp @@ -168,7 +168,7 @@ QWidget *DisassemblyContextMenu::parentForDialog() void DisassemblyContextMenu::addSetBaseMenu() { - setBaseMenu = addMenu(tr("Set Immediate Base to...")); + setBaseMenu = addMenu(tr("Set base of immediate value to..")); initAction(&actionSetBaseBinary, tr("Binary")); setBaseMenu->addAction(&actionSetBaseBinary); diff --git a/src/widgets/ColorThemeListView.cpp b/src/widgets/ColorThemeListView.cpp index 4f56ba17..84df6d67 100644 --- a/src/widgets/ColorThemeListView.cpp +++ b/src/widgets/ColorThemeListView.cpp @@ -400,8 +400,7 @@ const QMap optionInfoMap__ = { { "fname", { QObject::tr("Color of names of functions"), QObject::tr("Function name") } }, { "floc", { QObject::tr("Color of function location"), QObject::tr("Function location") } }, { "fline", - { QObject::tr( - "Color of ascii line in left side that shows what opcodes are belong to function"), + { QObject::tr("Color of the line which shows which opcodes belongs to a function"), QObject::tr("Function line") } }, { "flag", { QObject::tr("Color of flags (similar to bookmarks for offset)"), QObject::tr("Flag") } }, diff --git a/src/widgets/HexWidget.cpp b/src/widgets/HexWidget.cpp index d933b944..c9d09a71 100644 --- a/src/widgets/HexWidget.cpp +++ b/src/widgets/HexWidget.cpp @@ -160,7 +160,7 @@ HexWidget::HexWidget(QWidget *parent) connect(actionWriteCString, &QAction::triggered, this, &HexWidget::w_writeCString); actionsWriteString.append(actionWriteCString); - QAction *actionWrite64 = new QAction(tr("Write De\\Encoded Base64 string"), this); + QAction *actionWrite64 = new QAction(tr("Write a decoded or encoded Base64 string"), this); connect(actionWrite64, &QAction::triggered, this, &HexWidget::w_write64); actionsWriteString.append(actionWrite64); @@ -1407,7 +1407,7 @@ void HexWidget::w_writeRandom() } bool ok = false; - int nbytes = QInputDialog::getInt(this, tr("Write random"), tr("Number of bytes:"), size, 1, + int nbytes = QInputDialog::getInt(this, tr("Write random bytes"), tr("Number of bytes:"), size, 1, 0x7FFFFFFF, 1, &ok); if (!ok) { return; From a5fa4103b24178189608e212b8f3e046b4f00b65 Mon Sep 17 00:00:00 2001 From: Lucas Hosseini Date: Sun, 14 May 2023 06:59:13 +0200 Subject: [PATCH 229/240] Get rid of stale jump arrows in disassembly widget. (#3175) This commit clears arrows from edited instructions, in order to avoid stale arrows to remain drawn. closes #3114 --- src/widgets/DisassemblyWidget.cpp | 17 ++++++++++++++++- src/widgets/DisassemblyWidget.h | 2 ++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index ebbbfa0d..59adbaa7 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -132,7 +132,7 @@ DisassemblyWidget::DisassemblyWidget(MainWindow *main) connect(Core(), &CutterCore::functionRenamed, this, [this]() { refreshDisasm(); }); connect(Core(), SIGNAL(varsChanged()), this, SLOT(refreshDisasm())); connect(Core(), SIGNAL(asmOptionsChanged()), this, SLOT(refreshDisasm())); - connect(Core(), &CutterCore::instructionChanged, this, &DisassemblyWidget::refreshIfInRange); + connect(Core(), &CutterCore::instructionChanged, this, &DisassemblyWidget::instructionChanged); connect(Core(), &CutterCore::breakpointsChanged, this, &DisassemblyWidget::refreshIfInRange); connect(Core(), SIGNAL(refreshCodeViews()), this, SLOT(refreshDisasm())); @@ -226,6 +226,12 @@ void DisassemblyWidget::refreshIfInRange(RVA offset) } } +void DisassemblyWidget::instructionChanged(RVA offset) +{ + leftPanel->clearArrowFrom(offset); + refreshDisasm(); +} + void DisassemblyWidget::refreshDisasm(RVA offset) { if (!disasmRefresh->attemptRefresh(offset == RVA_INVALID ? nullptr : new RVA(offset))) { @@ -1006,3 +1012,12 @@ void DisassemblyLeftPanel::paintEvent(QPaintEvent *event) lastBeginOffset = lines.first().offset; } + +void DisassemblyLeftPanel::clearArrowFrom(RVA offset) +{ + auto it = std::find_if(arrows.begin(), arrows.end(), + [&](const Arrow &it) { return it.jmpFromOffset() == offset; }); + if (it != arrows.end()) { + arrows.erase(it); + } +} diff --git a/src/widgets/DisassemblyWidget.h b/src/widgets/DisassemblyWidget.h index 05a47579..8dadd4d4 100644 --- a/src/widgets/DisassemblyWidget.h +++ b/src/widgets/DisassemblyWidget.h @@ -53,6 +53,7 @@ public slots: protected slots: void on_seekChanged(RVA offset, CutterCore::SeekHistoryType type); void refreshIfInRange(RVA offset); + void instructionChanged(RVA offset); void refreshDisasm(RVA offset = RVA_INVALID); bool updateMaxLines(); @@ -156,6 +157,7 @@ public: DisassemblyLeftPanel(DisassemblyWidget *disas); void paintEvent(QPaintEvent *event) override; void wheelEvent(QWheelEvent *event) override; + void clearArrowFrom(RVA offset); private: DisassemblyWidget *disas; From 9bfe0c4e1df4c92762a6a24819aa5fd664013445 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Mon, 15 May 2023 20:37:45 +0800 Subject: [PATCH 230/240] Use Ubuntu 18.04 docker image (#3180) Co-authored-by: wargio --- .github/workflows/ci.yml | 263 ++++++++++++++++++++++++++++++--------- src/CMakeLists.txt | 2 +- 2 files changed, 202 insertions(+), 63 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 983d2b5b..a6d725ab 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -14,100 +14,164 @@ on: - dev - stable +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: - build: + build-linux: name: ${{ matrix.name }} - runs-on: ${{ matrix.os }} + runs-on: ubuntu-latest + container: + image: ${{ matrix.image }} + options: --privileged strategy: matrix: name: [ linux-x86_64, linux-x86_64-system-deps, linux-x86_64-qt6-system-deps, - macos-x86_64, - windows-x86_64, tarball ] include: - - name: windows-x86_64 - os: windows-2019 - package: true - system-deps: false - python-version: 3.7.x - name: linux-x86_64-system-deps # ensure that Cutter can be built at least in basic config on Ubuntu 18.04 using sytem libraries - os: ubuntu-18.04 + image: ubuntu:18.04 python-version: 3.6.x system-deps: true + package: false + tarball: false cc-override: '/usr/bin/gcc-7' cxx-override: '/usr/bin/g++-7' - name: linux-x86_64-qt6-system-deps # ensure that Cutter can be built at least in basic config on Ubuntu 22.04 using sytem libraries - os: ubuntu-22.04 + image: ubuntu:22.04 python-version: 3.10.x system-deps: true + package: false + tarball: false cc-override: '/usr/bin/gcc-12' cxx-override: '/usr/bin/g++-12' - name: linux-x86_64 - os: ubuntu-18.04 - python-version: 3.7.x - system-deps: false - package: true - cc-override: default - cxx-override: default - - name: macos-x86_64 - os: macos-latest - python-version: 3.7.x + image: ubuntu:18.04 + python-version: 3.6.x system-deps: false package: true + tarball: false cc-override: default cxx-override: default - name: tarball - python-version: 3.7.x - os: ubuntu-20.04 + python-version: 3.6.x + image: ubuntu:20.04 system-deps: false + package: false tarball: true # Prevent one job from pausing the rest fail-fast: false steps: + - name: set timezone + run: | + # Fix timezone on ubuntu to prevent user input request during the apt-get phase. + export TZ=UTC + ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + + - name: install latest git and cmake + shell: bash + run: | + set -e + apt-get -y update + echo "Using image: ${{ matrix.image }}" + + export GIT_VERSION="git-2.36.1" + export CMAKE_VERSION="3.25.3" + + apt-get -y install wget libcurl4-gnutls-dev libexpat1-dev gettext libz-dev libssl-dev build-essential + + wget "https://www.kernel.org/pub/software/scm/git/$GIT_VERSION.tar.gz" + tar -zxf "$GIT_VERSION.tar.gz" + + # build. + make -C "$GIT_VERSION" prefix=/usr install -j > "$GIT_VERSION/build.log" + + # ensure git is installed. + git version + + wget "https://github.com/Kitware/CMake/releases/download/v$CMAKE_VERSION/cmake-$CMAKE_VERSION-linux-x86_64.sh" + bash ./cmake-$CMAKE_VERSION-linux-x86_64.sh --skip-license --prefix=/usr + + # ensure cmake is installed. + cmake --version + + # cleanup dev environment. + rm -rf "$GIT_VERSION.tar.gz" "$GIT_VERSION" cmake-$CMAKE_VERSION-linux-x86_64.sh + unset CMAKE_VERSION + unset GIT_VERSION + - uses: actions/checkout@v3 with: submodules: recursive persist-credentials: false - - name: apt dependencies - if: contains(matrix.os, 'ubuntu') + + - name: apt cutter dependencies + shell: bash run: | - sudo apt-get update - sudo apt-get install libgraphviz-dev mesa-common-dev libxkbcommon-x11-dev ninja-build - if [[ "${{ matrix.os }}" = "ubuntu-18.04" || "${{ matrix.os }}" = "ubuntu-20.04" ]] - then + # install needed packages + apt-get -y install libgraphviz-dev \ + mesa-common-dev \ + libxkbcommon-x11-dev \ + ninja-build \ + python3-pip \ + curl \ + libpcre2-dev \ + libfuse2 \ + pkg-config + + if [ "${{ matrix.image }}" = "ubuntu:18.04" ]; then # install additional packages needed for appimage - sudo apt-get install libxcb1-dev libxkbcommon-dev libxcb-*-dev libegl1 libclang-8-dev llvm-8 + apt-get -y install gcc-7 \ + libglu1-mesa-dev \ + freeglut3-dev \ + mesa-common-dev + fi - if [[ "${{ matrix.os }}" = "ubuntu-18.04" && "${{ matrix.system-deps }}" = "true" ]] - then - sudo apt-get install qt5-default libqt5svg5-dev qttools5-dev qttools5-dev-tools + if [ "${{ matrix.image }}" = "ubuntu:18.04" ] || [ "${{ matrix.image }}" = "ubuntu:20.04" ]; then + # install additional packages needed for appimage + apt-get -y install libxcb1-dev \ + libxkbcommon-dev \ + libxcb-*-dev \ + libegl1 \ + libclang-8-dev \ + llvm-8 + ln -s /usr/bin/llvm-config-8 /usr/bin/llvm-config fi - if [[ "${{ matrix.os }}" = "ubuntu-22.04" ]] - then - sudo apt-get install libclang-12-dev llvm-12 qt6-base-dev qt6-tools-dev \ - qt6-tools-dev-tools libqt6svg6-dev libqt6core5compat6-dev libqt6svgwidgets6 qt6-l10n-tools + if [ "${{ matrix.image }}" = "ubuntu:18.04" ] && [ "${{ matrix.system-deps }}" = "true" ]; then + apt-get -y install qt5-default \ + libqt5svg5-dev \ + qttools5-dev \ + qttools5-dev-tools + fi + if [ "${{ matrix.image }}" = "ubuntu:22.04" ]; then + apt-get -y install libclang-12-dev \ + llvm-12 \ + qt6-base-dev \ + qt6-tools-dev \ + qt6-tools-dev-tools \ + libqt6svg6-dev \ + libqt6core5compat6-dev \ + libqt6svgwidgets6 \ + qt6-l10n-tools \ + gcc-12 \ + g++-12 fi - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python-version }} - - name: homebrew dependencies - if: contains(matrix.os, 'macos') - run: | - cd scripts - rm /usr/local/bin/2to3* # symlink to some kind of existing python2.7 installation conflicts with brew python3 which gets installed as indirect dependency - brew bundle - name: py dependencies run: | - python3 -m pip install -U pip==21.3.1 - pip install meson==0.61.5 # https://github.com/rizinorg/cutter/runs/7170222817?check_suite_focus=true + # https://github.com/rizinorg/cutter/runs/7170222817?check_suite_focus=true + python3 -m pip install meson==0.61.5 - name: Prepare package id shell: bash run: | - if [[ "${{ startsWith(github.event.ref, 'refs/tags')}}" = "true" ]] + if [ "${{ startsWith(github.event.ref, 'refs/tags')}}" = "true" ] then PACKAGE_ID="${{ github.event.ref }}" else @@ -116,17 +180,17 @@ jobs: PACKAGE_ID=${PACKAGE_ID##refs/tags/} echo PACKAGE_ID=$PACKAGE_ID >> $GITHUB_ENV - name: cmake ubuntu - if: contains(matrix.os, 'ubuntu') + shell: bash run: | - if [[ "${{ matrix.system-deps }}" = "false" ]] + if [ "${{ matrix.system-deps }}" = "false" ] then scripts/fetch_deps.sh - source cutter-deps/env.sh + . cutter-deps/env.sh export PKG_CONFIG_PATH="$CUTTER_DEPS_PYTHON_PREFIX/lib/pkgconfig:${PKG_CONFIG_PATH:-}" export LD_LIBRARY_PATH="`llvm-config --libdir`:$LD_LIBRARY_PATH" fi - set -euo pipefail #TODO: move to top once cutter-deps doesn't fail - if [[ "${{ matrix.cc-override }}" != "default" ]] + set -e #TODO: move to top once cutter-deps doesn't fail + if [ "${{ matrix.cc-override }}" != "default" ] then export CC="${{matrix.cc-override}}" export CXX="${{matrix.cxx-override}}" @@ -134,8 +198,7 @@ jobs: mkdir build cd build - cmake --version - if [[ "${{ matrix.system-deps }}" = "false" ]] + if [ "${{ matrix.system-deps }}" = "false" ] then cmake \ -G Ninja \ @@ -149,6 +212,7 @@ jobs: -DCUTTER_USE_BUNDLED_RIZIN=ON \ -DCUTTER_APPIMAGE_BUILD=ON \ -DCUTTER_ENABLE_PACKAGING=ON \ + -DCUTTER_ENABLE_KSYNTAXHIGHLIGHTING=OFF \ -DCUTTER_ENABLE_SIGDB=ON \ -DCUTTER_ENABLE_DEPENDENCY_DOWNLOADS=ON \ -DCUTTER_PACKAGE_RZ_GHIDRA=ON \ @@ -159,7 +223,7 @@ jobs: -DCMAKE_INSTALL_PREFIX=appdir/usr \ -DCMAKE_INSTALL_RPATH_USE_LINK_PATH=ON \ .. - elif [[ "${{ matrix.os }}" = "ubuntu-22.04" ]] + elif [ "${{ matrix.image }}" = "ubuntu:22.04" ] then cmake \ -G Ninja \ @@ -175,7 +239,7 @@ jobs: .. fi ninja - if [[ "${{ matrix.package || false }}" = "true" ]] + if [ "${{ matrix.package }}" = "true" ] then export CUTTER_VERSION=$(python ../scripts/get_version.py) export VERSION=$CUTTER_VERSION @@ -200,6 +264,89 @@ jobs: echo PACKAGE_PATH=build/$APPIMAGE_FILE >> $GITHUB_ENV echo UPLOAD_ASSET_TYPE=application/x-executable >> $GITHUB_ENV fi + - name: Create tarball + if: matrix.tarball + shell: bash + run: | + scripts/tarball.sh "Cutter-${PACKAGE_ID}" + echo PACKAGE_NAME=Cutter-${PACKAGE_ID}-src.tar.gz >> $GITHUB_ENV + echo PACKAGE_PATH=Cutter-${PACKAGE_ID}-src.tar.gz >> $GITHUB_ENV + echo UPLOAD_ASSET_TYPE=application/gzip >> $GITHUB_ENV + - uses: actions/upload-artifact@v3 + if: env.PACKAGE_NAME != null + with: + name: ${{ env.PACKAGE_NAME }} + path: ${{ env.PACKAGE_PATH }} + - name: Get release + if: github.event_name == 'push' && startsWith(github.event.ref, 'refs/tags') + id: get_release + uses: rizinorg/gha-get-release@c8074dd5d13ddd0a194d8c9205a1466973c7dc0d + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - name: Upload release assets + if: steps.get_release.outputs.upload_url != null && env.PACKAGE_NAME != null + uses: actions/upload-release-asset@v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.get_release.outputs.upload_url }} + asset_path: ${{ env.PACKAGE_PATH }} + asset_name: ${{ env.PACKAGE_NAME }} + asset_content_type: ${{ env.UPLOAD_ASSET_TYPE }} + + build: + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + strategy: + matrix: + name: [ + macos-x86_64, + windows-x86_64, + ] + include: + - name: windows-x86_64 + os: windows-2019 + package: true + system-deps: false + python-version: 3.7.x + - name: macos-x86_64 + os: macos-latest + python-version: 3.7.x + system-deps: false + package: true + cc-override: default + cxx-override: default + # Prevent one job from pausing the rest + fail-fast: false + steps: + - uses: actions/checkout@v3 + with: + submodules: recursive + persist-credentials: false + - uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: homebrew dependencies + if: contains(matrix.os, 'macos') + run: | + cd scripts + rm /usr/local/bin/2to3* # symlink to some kind of existing python2.7 installation conflicts with brew python3 which gets installed as indirect dependency + brew bundle + - name: py dependencies + run: | + python3 -m pip install -U pip==21.3.1 + pip install meson==0.61.5 # https://github.com/rizinorg/cutter/runs/7170222817?check_suite_focus=true + - name: Prepare package id + shell: bash + run: | + if [[ "${{ startsWith(github.event.ref, 'refs/tags')}}" = "true" ]] + then + PACKAGE_ID="${{ github.event.ref }}" + else + PACKAGE_ID="git-`date "+%Y-%m-%d"`-${{ format('{0}', github.sha) }}" + fi + PACKAGE_ID=${PACKAGE_ID##refs/tags/} + echo PACKAGE_ID=$PACKAGE_ID >> $GITHUB_ENV - name: cmake macos shell: bash if: contains(matrix.os, 'macos') @@ -280,14 +427,6 @@ jobs: echo PACKAGE_NAME=%PACKAGE_NAME%.zip >> %GITHUB_ENV% echo PACKAGE_PATH=build/%PACKAGE_NAME%.zip >> %GITHUB_ENV% echo UPLOAD_ASSET_TYPE=application/zip >> %GITHUB_ENV% - - name: Create tarball - if: matrix.tarball - shell: bash - run: | - scripts/tarball.sh "Cutter-${PACKAGE_ID}" - echo PACKAGE_NAME=Cutter-${PACKAGE_ID}-src.tar.gz >> $GITHUB_ENV - echo PACKAGE_PATH=Cutter-${PACKAGE_ID}-src.tar.gz >> $GITHUB_ENV - echo UPLOAD_ASSET_TYPE=application/gzip >> $GITHUB_ENV - uses: actions/upload-artifact@v3 if: env.PACKAGE_NAME != null with: diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index dd8f524e..19018beb 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -517,7 +517,7 @@ if(CUTTER_ENABLE_PYTHON) endif() configure_file("${BINDINGS_SRC_DIR}/bindings.txt.in" "${BINDINGS_BUILD_DIR}/bindings.txt") - add_compile_definitions(WIN32_LEAN_AND_MEAN) + add_definitions(-DWIN32_LEAN_AND_MEAN) endif() endif() From 48c8e0c44d4d2a563087171384df7efe8c0b86dc Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Sun, 29 May 2022 16:41:54 +0800 Subject: [PATCH 231/240] Allow building Python bindings with Qt6 --- CMakeLists.txt | 29 +++++++++++++++++++++-------- docs/source/building.rst | 2 +- src/CMakeLists.txt | 14 ++++++++++++-- 3 files changed, 34 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 60cd6c53..8145e362 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,7 +14,7 @@ option(CUTTER_USE_BUNDLED_RIZIN "Use rizin from ./rizin submodule instead of sea option(CUTTER_USE_ADDITIONAL_RIZIN_PATHS "Search rizin in additional paths which are not part of default system library paths.\ Disable this option if you are linking against rizin pacakged as proper system library or in a custom path and additional are paths causing problems." ON) option(CUTTER_ENABLE_PYTHON "Enable Python integration. Requires Python >= ${CUTTER_PYTHON_MIN}." OFF) -option(CUTTER_ENABLE_PYTHON_BINDINGS "Enable generating Python bindings with Shiboken2. Unused if CUTTER_ENABLE_PYTHON=OFF." OFF) +option(CUTTER_ENABLE_PYTHON_BINDINGS "Enable generating Python bindings with Shiboken. Unused if CUTTER_ENABLE_PYTHON=OFF." OFF) option(CUTTER_APPIMAGE_BUILD "Enable Appimage specific changes. Doesn't cause building of Appimage itself." OFF) tri_option(CUTTER_ENABLE_KSYNTAXHIGHLIGHTING "Use KSyntaxHighlighting" AUTO) tri_option(CUTTER_ENABLE_GRAPHVIZ "Enable use of graphviz for graph layout" AUTO) @@ -100,16 +100,29 @@ if(CUTTER_ENABLE_PYTHON) add_definitions(-DCUTTER_ENABLE_PYTHON) if(CUTTER_ENABLE_PYTHON_BINDINGS) - # 5.12.3 => 5.12 - if("${Qt5_VERSION}" MATCHES "^([0-9]+\\.[0-9]+)\\.[0-9]+") - set(Shiboken2_VERSION_REQUIRED "${CMAKE_MATCH_1}") + if (CUTTER_QT6) + # 6.12.3 => 6.12 + if("${Qt6_VERSION}" MATCHES "^([0-9]+\\.[0-9]+)\\.[0-9]+") + set(Shiboken6_VERSION_REQUIRED "${CMAKE_MATCH_1}") + else() + message(FATAL_ERROR "Failed to recognize Qt version") + endif() + find_package(Shiboken6 "${Shiboken6_VERSION_REQUIRED}" REQUIRED) + find_package(Shiboken6Tools "${Shiboken6_VERSION_REQUIRED}" REQUIRED) + find_package(PySide6 "${Shiboken6_VERSION_REQUIRED}" REQUIRED) + get_target_property(PYSIDE_INCLUDE_DIR PySide6::pyside6 INTERFACE_INCLUDE_DIRECTORIES) else() - message(FATAL_ERROR "Failed to recognize Qt version") + # 5.12.3 => 5.12 + if("${Qt5_VERSION}" MATCHES "^([0-9]+\\.[0-9]+)\\.[0-9]+") + set(Shiboken2_VERSION_REQUIRED "${CMAKE_MATCH_1}") + else() + message(FATAL_ERROR "Failed to recognize Qt version") + endif() + find_package(Shiboken2 "${Shiboken2_VERSION_REQUIRED}" REQUIRED) + find_package(PySide2 "${Shiboken2_VERSION_REQUIRED}" REQUIRED) + get_target_property(PYSIDE_INCLUDE_DIR PySide2::pyside2 INTERFACE_INCLUDE_DIRECTORIES) endif() - find_package(Shiboken2 "${Shiboken2_VERSION_REQUIRED}" REQUIRED) - find_package(PySide2 "${Shiboken2_VERSION_REQUIRED}" REQUIRED) - get_target_property(PYSIDE_INCLUDE_DIR PySide2::pyside2 INTERFACE_INCLUDE_DIRECTORIES) list(GET PYSIDE_INCLUDE_DIR 0 PYSIDE_INCLUDE_DIR) include_directories(${PYSIDE_INCLUDE_DIR} ${PYSIDE_INCLUDE_DIR}/QtCore diff --git a/docs/source/building.rst b/docs/source/building.rst index 924e638e..762cdd31 100644 --- a/docs/source/building.rst +++ b/docs/source/building.rst @@ -247,7 +247,7 @@ Note that there are some major building options available: * ``CUTTER_USE_BUNDLED_RIZIN`` automatically compile Rizin from submodule (Enabled by default). * ``CUTTER_ENABLE_PYTHON`` compile with Python support. -* ``CUTTER_ENABLE_PYTHON_BINDINGS`` automatically generate Python Bindings with Shiboken2, required for Python plugins! +* ``CUTTER_ENABLE_PYTHON_BINDINGS`` automatically generate Python Bindings with Shiboken, required for Python plugins! * ``CUTTER_ENABLE_KSYNTAXHIGHLIGHTING`` use KSyntaxHighlighting for code highlighting. * ``CUTTER_ENABLE_GRAPHVIZ`` enable Graphviz for graph layouts. * ``CUTTER_EXTRA_PLUGIN_DIRS`` List of addition plugin locations. Useful when preparing package for Linux distros that have strict package layout rules. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 19018beb..404f5d14 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -408,8 +408,14 @@ if(CUTTER_ENABLE_PYTHON_BINDINGS) list(APPEND SHIBOKEN_OPTIONS --avoid-protected-hack) endif() + if (CUTTER_QT6) + set(SHIBOKEN_COMMAND Shiboken6::shiboken6) + else() + set(SHIBOKEN_COMMAND Shiboken2::shiboken2) + endif() + add_custom_command(OUTPUT ${BINDINGS_SOURCE} - COMMAND Shiboken2::shiboken2 --project-file="${BINDINGS_BUILD_DIR}/bindings.txt" ${SHIBOKEN_OPTIONS} ${SHIBOKEN_EXTRA_OPTIONS} + COMMAND "${SHIBOKEN_COMMAND}" --project-file="${BINDINGS_BUILD_DIR}/bindings.txt" ${SHIBOKEN_OPTIONS} ${SHIBOKEN_EXTRA_OPTIONS} DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/bindings/bindings.xml" "${BINDINGS_BUILD_DIR}/bindings.txt" IMPLICIT_DEPENDS CXX "${CMAKE_CURRENT_SOURCE_DIR}/bindings/bindings.h" COMMENT "Generating Python bindings with shiboken2") @@ -487,7 +493,11 @@ if(CUTTER_ENABLE_PYTHON) endif() target_link_libraries(Cutter PRIVATE ${PYTHON_LIBRARIES}) if(CUTTER_ENABLE_PYTHON_BINDINGS) - target_link_libraries(Cutter PRIVATE Shiboken2::libshiboken PySide2::pyside2) + if (CUTTER_QT6) + target_link_libraries(Cutter PRIVATE Shiboken6::libshiboken PySide6::pyside6) + else() + target_link_libraries(Cutter PRIVATE Shiboken2::libshiboken PySide2::pyside2) + endif() get_target_property(RAW_BINDINGS_INCLUDE_DIRS Cutter INCLUDE_DIRECTORIES) if(NOT CUTTER_USE_BUNDLED_RIZIN) From e78a1fe9ed7292abbdbd49db09250b290bf4565c Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Mon, 13 Mar 2023 14:45:54 +0800 Subject: [PATCH 232/240] Add FindPySide6 CMake module --- cmake/FindPySide6.cmake | 68 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 cmake/FindPySide6.cmake diff --git a/cmake/FindPySide6.cmake b/cmake/FindPySide6.cmake new file mode 100644 index 00000000..d072918c --- /dev/null +++ b/cmake/FindPySide6.cmake @@ -0,0 +1,68 @@ + +set(_module PySide6) + +find_package(${_module} ${${_module}_FIND_VERSION} CONFIG QUIET) +set(_lib_target ${_module}::pyside6) + +if(NOT ${_module}_FOUND) + include(PythonInfo) + find_python_site_packages(PYTHON_SITE_PACKAGES) + get_python_extension_suffix(PYTHON_EXTENSION_SUFFIX) + + find_library(PYSIDE_LIBRARY + NAMES + "pyside6${PYTHON_EXTENSION_SUFFIX}" + "pyside6${PYTHON_EXTENSION_SUFFIX}.${${_module}_FIND_VERSION_MAJOR}.${${_module}_FIND_VERSION_MINOR}" + PATH_SUFFIXES "${PYTHON_SITE_PACKAGES}/PySide6") + + find_path(PYSIDE_INCLUDE_DIR + pyside.h + PATH_SUFFIXES "${PYTHON_SITE_PACKAGES}/PySide6/include") + + find_path(PYSIDE_TYPESYSTEMS + typesystem_core.xml + PATH_SUFFIXES "${PYTHON_SITE_PACKAGES}/PySide6/typesystems") +endif() + +if(TARGET ${_lib_target}) + get_target_property(_is_imported ${_lib_target} IMPORTED) + if(_is_imported) + get_target_property(_imported_location ${_lib_target} IMPORTED_LOCATION) + if(NOT _imported_location) + message(STATUS "Target ${_lib_target} does not specify its IMPORTED_LOCATION! Trying to find it ourselves...") + set(_find_args) + if(${_module}_CONFIG) + get_filename_component(_pyside6_lib_dir "${${_module}_CONFIG}/../../../" ABSOLUTE) + set(_find_args PATHS "${_pyside6_lib_dir}") + endif() + find_library(PYSIDE_LIBRARY + NAMES + "pyside6${PYTHON_CONFIG_SUFFIX}" + "pyside6${PYTHON_CONFIG_SUFFIX}.${${_module}_FIND_VERSION_MAJOR}.${${_module}_FIND_VERSION_MINOR}" + ${_find_args}) + if(NOT PYSIDE_LIBRARY) + set(_message_type WARNING) + if(${_module}_FIND_REQUIRED) + set(_message_type FATAL_ERROR) + endif() + message(${_message_type} "Failed to manually find library for ${_module}") + return() + endif() + message(STATUS "IMPORTED_LOCATION for ${_lib_target} found: ${PYSIDE_LIBRARY}") + set_target_properties(${_lib_target} PROPERTIES IMPORTED_LOCATION "${PYSIDE_LIBRARY}") + endif() + endif() +else() + include(FindPackageHandleStandardArgs) + find_package_handle_standard_args(${_module} + FOUND_VAR ${_module}_FOUND + REQUIRED_VARS PYSIDE_LIBRARY PYSIDE_INCLUDE_DIR PYSIDE_TYPESYSTEMS + VERSION_VAR ${_module}_VERSION) + + add_library(${_module}::pyside6 INTERFACE IMPORTED) + set_target_properties(${_module}::pyside6 PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${PYSIDE_INCLUDE_DIR}" + INTERFACE_LINK_LIBRARIES "${PYSIDE_LIBRARY}") +endif() + +mark_as_advanced(PYSIDE_INCLUDE_DIR PYSIDE_LIBRARY PYSIDE_BINARY) From 553a8eef5c16198c8427163b9324fe227ddaa374 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Mon, 13 Feb 2023 17:41:48 +0800 Subject: [PATCH 233/240] Specify include paths for Shiboken --- src/CMakeLists.txt | 35 +++++++++++++++++++++++++++++++++-- 1 file changed, 33 insertions(+), 2 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 404f5d14..1533719e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -386,6 +386,8 @@ set(QRC_FILES themes/lightstyle/light.qrc ) +set(CUTTER_INCLUDE_DIRECTORIES core widgets common plugins menus .) + if (CUTTER_ENABLE_PYTHON) list(APPEND SOURCES common/QtResImporter.cpp common/PythonManager.cpp common/PythonAPI.cpp) list(APPEND HEADER_FILES common/QtResImporter.h common/PythonManager.h common/PythonAPI.h) @@ -403,7 +405,33 @@ if(CUTTER_ENABLE_PYTHON_BINDINGS) include_directories("${BINDINGS_BUILD_DIR}/CutterBindings") + set(SHIBOKEN_INCLUDE_DIRS "") + if(APPLE AND _qt6Core_install_prefix) + list(APPEND BINDINGS_INCLUDE_DIRS "${_qt6Core_install_prefix}/include") + list(APPEND BINDINGS_INCLUDE_DIRS "${_qt6Core_install_prefix}/include/QtCore") + list(APPEND BINDINGS_INCLUDE_DIRS "${_qt6Core_install_prefix}/include/QtGui") + list(APPEND BINDINGS_INCLUDE_DIRS "${_qt6Core_install_prefix}/include/QtWidgets") + endif() + + if (CUTTER_QT6) + list(APPEND SHIBOKEN_INCLUDE_DIRS ${Qt6Core_INCLUDE_DIRS} ${Qt6Widgets_INCLUDE_DIRS} ${Qt6Gui_INCLUDE_DIRS}) + else() + list(APPEND SHIBOKEN_INCLUDE_DIRS ${Qt5Core_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS}) + endif() + + foreach(_dir ${CUTTER_INCLUDE_DIRECTORIES}) + list(APPEND SHIBOKEN_INCLUDE_DIRS + $ + $ + ) + endforeach() + list(APPEND SHIBOKEN_INCLUDE_DIRS ${Rizin_INCLUDE_DIRS}) + if (NOT WIN32) + string(REPLACE ";" ":" SHIBOKEN_INCLUDE_DIRS "${SHIBOKEN_INCLUDE_DIRS}") + endif() + set(SHIBOKEN_OPTIONS) + list(APPEND SHIBOKEN_OPTIONS --include-paths="${SHIBOKEN_INCLUDE_DIRS}") if (WIN32) list(APPEND SHIBOKEN_OPTIONS --avoid-protected-hack) endif() @@ -458,7 +486,6 @@ target_compile_definitions(Cutter PRIVATE CUTTER_SOURCE_BUILD) # Set Cutter as the startup project in Visual Studio set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT Cutter) -set(CUTTER_INCLUDE_DIRECTORIES core widgets common plugins menus .) foreach(_dir ${CUTTER_INCLUDE_DIRECTORIES}) target_include_directories(Cutter PUBLIC $ @@ -519,7 +546,11 @@ if(CUTTER_ENABLE_PYTHON) list(APPEND BINDINGS_INCLUDE_DIRS "${_qt5Core_install_prefix}/include/QtGui") list(APPEND BINDINGS_INCLUDE_DIRS "${_qt5Core_install_prefix}/include/QtWidgets") endif() - list(APPEND BINDINGS_INCLUDE_DIRS ${Qt5Core_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS}) + if (CUTTER_QT6) + list(APPEND BINDINGS_INCLUDE_DIRS ${Qt6Core_INCLUDE_DIRS} ${Qt6Widgets_INCLUDE_DIRS} ${Qt6Gui_INCLUDE_DIRS}) + else() + list(APPEND BINDINGS_INCLUDE_DIRS ${Qt5Core_INCLUDE_DIRS} ${Qt5Widgets_INCLUDE_DIRS} ${Qt5Gui_INCLUDE_DIRS}) + endif() list(APPEND BINDINGS_INCLUDE_DIRS ${Rizin_INCLUDE_DIRS}) list(APPEND BINDINGS_INCLUDE_DIRS "${CMAKE_CURRENT_SOURCE_DIR}") if (NOT WIN32) From 93f88263a0b606579b74d3aef798998804e4d3c5 Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Thu, 16 Feb 2023 12:42:32 +0800 Subject: [PATCH 234/240] Address Python and PySide API changes --- CMakeLists.txt | 2 ++ src/common/PythonManager.cpp | 7 ++++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 8145e362..d567a49e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,6 +111,8 @@ if(CUTTER_ENABLE_PYTHON) find_package(Shiboken6Tools "${Shiboken6_VERSION_REQUIRED}" REQUIRED) find_package(PySide6 "${Shiboken6_VERSION_REQUIRED}" REQUIRED) get_target_property(PYSIDE_INCLUDE_DIR PySide6::pyside6 INTERFACE_INCLUDE_DIRECTORIES) + # Check the presence of "pysidecleanup.h" + CHECK_INCLUDE_FILE_CXX("pysidecleanup.h" HAVE_PYSIDECLEANUP) else() # 5.12.3 => 5.12 if("${Qt5_VERSION}" MATCHES "^([0-9]+\\.[0-9]+)\\.[0-9]+") diff --git a/src/common/PythonManager.cpp b/src/common/PythonManager.cpp index 5b2ecd16..8e38a24b 100644 --- a/src/common/PythonManager.cpp +++ b/src/common/PythonManager.cpp @@ -13,6 +13,10 @@ #ifdef CUTTER_ENABLE_PYTHON_BINDINGS # include # include +#ifdef HAVE_PYSIDECLEANUP + // This header is introduced in PySide 6 +# include +#endif # include #endif @@ -72,6 +76,7 @@ void PythonManager::initialize() PyImport_AppendInittab("CutterBindings", &PyInit_CutterBindings); #endif Py_Initialize(); + // This function is deprecated does nothing starting from Python 3.9 PyEval_InitThreads(); pyThreadStateCounter = 1; // we have the thread now => 1 @@ -159,7 +164,7 @@ void PythonManager::addPythonPath(char *path) if (!append) { return; } - PyEval_CallFunction(append, "(s)", path); + PyObject_CallFunction(append, "(s)", path); saveThread(); } From aa40f6945823d08e171f5e16159d895e8cbd5ccc Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Thu, 16 Feb 2023 12:43:03 +0800 Subject: [PATCH 235/240] Specify PySide version in bindings template --- CMakeLists.txt | 4 ++++ src/CMakeLists.txt | 18 ++++++++++-------- src/bindings/bindings.txt.in | 4 ++-- src/bindings/{bindings.xml => bindings.xml.in} | 2 +- src/bindings/src_list.py | 2 +- 5 files changed, 18 insertions(+), 12 deletions(-) rename src/bindings/{bindings.xml => bindings.xml.in} (97%) diff --git a/CMakeLists.txt b/CMakeLists.txt index d567a49e..fa5bbbe7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -110,9 +110,13 @@ if(CUTTER_ENABLE_PYTHON) find_package(Shiboken6 "${Shiboken6_VERSION_REQUIRED}" REQUIRED) find_package(Shiboken6Tools "${Shiboken6_VERSION_REQUIRED}" REQUIRED) find_package(PySide6 "${Shiboken6_VERSION_REQUIRED}" REQUIRED) + get_target_property(LIBSHIBOKEN_INCLUDE_DIRS Shiboken6::libshiboken INTERFACE_INCLUDE_DIRECTORIES) get_target_property(PYSIDE_INCLUDE_DIR PySide6::pyside6 INTERFACE_INCLUDE_DIRECTORIES) # Check the presence of "pysidecleanup.h" + include(CheckIncludeFileCXX) + set(CMAKE_REQUIRED_INCLUDES "${PYSIDE_INCLUDE_DIR};${LIBSHIBOKEN_INCLUDE_DIRS}") CHECK_INCLUDE_FILE_CXX("pysidecleanup.h" HAVE_PYSIDECLEANUP) + add_compile_definitions("HAVE_PYSIDECLEANUP=${HAVE_PYSIDECLEANUP}") else() # 5.12.3 => 5.12 if("${Qt5_VERSION}" MATCHES "^([0-9]+\\.[0-9]+)\\.[0-9]+") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 1533719e..009b2962 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -394,10 +394,18 @@ if (CUTTER_ENABLE_PYTHON) endif() if(CUTTER_ENABLE_PYTHON_BINDINGS) + if (CUTTER_QT6) + set(PYSIDE_NAME PySide6) + set(SHIBOKEN_COMMAND Shiboken6::shiboken6) + else() + set(PYSIDE_NAME PySide2) + set(SHIBOKEN_COMMAND Shiboken2::shiboken2) + endif() + set(BINDINGS_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}/bindings") set(BINDINGS_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/bindings") - configure_file("${BINDINGS_SRC_DIR}/bindings.xml" "${BINDINGS_BUILD_DIR}/bindings.xml" COPYONLY) # trigger reconfigure if file changes + configure_file("${BINDINGS_SRC_DIR}/bindings.xml.in" "${BINDINGS_BUILD_DIR}/bindings.xml") execute_process(COMMAND "${PYTHON_EXECUTABLE}" "${BINDINGS_SRC_DIR}/src_list.py" cmake "${BINDINGS_BUILD_DIR}" OUTPUT_VARIABLE BINDINGS_SOURCE) @@ -436,15 +444,9 @@ if(CUTTER_ENABLE_PYTHON_BINDINGS) list(APPEND SHIBOKEN_OPTIONS --avoid-protected-hack) endif() - if (CUTTER_QT6) - set(SHIBOKEN_COMMAND Shiboken6::shiboken6) - else() - set(SHIBOKEN_COMMAND Shiboken2::shiboken2) - endif() - add_custom_command(OUTPUT ${BINDINGS_SOURCE} COMMAND "${SHIBOKEN_COMMAND}" --project-file="${BINDINGS_BUILD_DIR}/bindings.txt" ${SHIBOKEN_OPTIONS} ${SHIBOKEN_EXTRA_OPTIONS} - DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/bindings/bindings.xml" "${BINDINGS_BUILD_DIR}/bindings.txt" + DEPENDS "${BINDINGS_BUILD_DIR}/bindings.xml" "${BINDINGS_BUILD_DIR}/bindings.txt" IMPLICIT_DEPENDS CXX "${CMAKE_CURRENT_SOURCE_DIR}/bindings/bindings.h" COMMENT "Generating Python bindings with shiboken2") else() diff --git a/src/bindings/bindings.txt.in b/src/bindings/bindings.txt.in index dd478889..5eb103ee 100644 --- a/src/bindings/bindings.txt.in +++ b/src/bindings/bindings.txt.in @@ -3,7 +3,7 @@ generator-set = shiboken header-file = ${BINDINGS_SRC_DIR}/bindings.h -typesystem-file = ${BINDINGS_SRC_DIR}/bindings.xml +typesystem-file = ${BINDINGS_BUILD_DIR}/bindings.xml output-directory = ${BINDINGS_BUILD_DIR} @@ -14,4 +14,4 @@ typesystem-paths = ${PYSIDE_TYPESYSTEMS} enable-parent-ctor-heuristic enable-pyside-extensions enable-return-value-heuristic -use-isnull-as-nb_nonzero \ No newline at end of file +use-isnull-as-nb_nonzero diff --git a/src/bindings/bindings.xml b/src/bindings/bindings.xml.in similarity index 97% rename from src/bindings/bindings.xml rename to src/bindings/bindings.xml.in index 36386558..0fa194a9 100644 --- a/src/bindings/bindings.xml +++ b/src/bindings/bindings.xml.in @@ -30,7 +30,7 @@ PyErr_Print(); return QString(); } - PythonToCppFunc pythonToCpp = Shiboken::Conversions::isPythonToCppConvertible(SbkPySide2_QtCoreTypeConverters[SBK_QSTRING_IDX], pyResult); + PythonToCppFunc pythonToCpp = Shiboken::Conversions::isPythonToCppConvertible(Sbk${PYSIDE_NAME}_QtCoreTypeConverters[SBK_QSTRING_IDX], pyResult); if (!pythonToCpp) { Shiboken::warning(PyExc_RuntimeWarning, 2, "Invalid return value for plugin metadata VAR_NAME, expected %s, got %s.", "QString", Py_TYPE(pyResult)->tp_name); return ::QString(); diff --git a/src/bindings/src_list.py b/src/bindings/src_list.py index 3175b39e..69e06f5a 100755 --- a/src/bindings/src_list.py +++ b/src/bindings/src_list.py @@ -9,7 +9,7 @@ script_path = os.path.dirname(os.path.realpath(__file__)) def get_cpp_files_gen(args, include_package=True): - ts_tree = et.parse(os.path.join(script_path, "bindings.xml")) + ts_tree = et.parse(os.path.join(script_path, "bindings.xml.in")) ts_root = ts_tree.getroot() package = ts_root.attrib["package"] From da7fc439db8b76ec10a3af460d94fb422b014ddb Mon Sep 17 00:00:00 2001 From: Anton Kochkov Date: Fri, 17 Feb 2023 21:50:37 +0800 Subject: [PATCH 236/240] Rename PYSIDE_INCLUDE_DIR to PYSIDE_INCLUDE_DIRS --- CMakeLists.txt | 17 +++++++++-------- cmake/FindPySide2.cmake | 2 +- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa5bbbe7..38f18f17 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,10 +111,10 @@ if(CUTTER_ENABLE_PYTHON) find_package(Shiboken6Tools "${Shiboken6_VERSION_REQUIRED}" REQUIRED) find_package(PySide6 "${Shiboken6_VERSION_REQUIRED}" REQUIRED) get_target_property(LIBSHIBOKEN_INCLUDE_DIRS Shiboken6::libshiboken INTERFACE_INCLUDE_DIRECTORIES) - get_target_property(PYSIDE_INCLUDE_DIR PySide6::pyside6 INTERFACE_INCLUDE_DIRECTORIES) + get_target_property(PYSIDE_INCLUDE_DIRS PySide6::pyside6 INTERFACE_INCLUDE_DIRECTORIES) # Check the presence of "pysidecleanup.h" include(CheckIncludeFileCXX) - set(CMAKE_REQUIRED_INCLUDES "${PYSIDE_INCLUDE_DIR};${LIBSHIBOKEN_INCLUDE_DIRS}") + set(CMAKE_REQUIRED_INCLUDES "${PYSIDE_INCLUDE_DIRS};${LIBSHIBOKEN_INCLUDE_DIRS}") CHECK_INCLUDE_FILE_CXX("pysidecleanup.h" HAVE_PYSIDECLEANUP) add_compile_definitions("HAVE_PYSIDECLEANUP=${HAVE_PYSIDECLEANUP}") else() @@ -126,14 +126,15 @@ if(CUTTER_ENABLE_PYTHON) endif() find_package(Shiboken2 "${Shiboken2_VERSION_REQUIRED}" REQUIRED) find_package(PySide2 "${Shiboken2_VERSION_REQUIRED}" REQUIRED) - get_target_property(PYSIDE_INCLUDE_DIR PySide2::pyside2 INTERFACE_INCLUDE_DIRECTORIES) + get_target_property(PYSIDE_INCLUDE_DIRS PySide2::pyside2 INTERFACE_INCLUDE_DIRECTORIES) endif() - list(GET PYSIDE_INCLUDE_DIR 0 PYSIDE_INCLUDE_DIR) - include_directories(${PYSIDE_INCLUDE_DIR} - ${PYSIDE_INCLUDE_DIR}/QtCore - ${PYSIDE_INCLUDE_DIR}/QtGui - ${PYSIDE_INCLUDE_DIR}/QtWidgets) + foreach(_dir IN LISTS PYSIDE_INCLUDE_DIRS) + include_directories(${_dir} + ${_dir}/QtCore + ${_dir}/QtGui + ${_dir}/QtWidgets) + endforeach() add_definitions(-DCUTTER_ENABLE_PYTHON_BINDINGS) endif() diff --git a/cmake/FindPySide2.cmake b/cmake/FindPySide2.cmake index 1b6faf40..d4843f97 100644 --- a/cmake/FindPySide2.cmake +++ b/cmake/FindPySide2.cmake @@ -65,4 +65,4 @@ else() INTERFACE_LINK_LIBRARIES "${PYSIDE_LIBRARY}") endif() -mark_as_advanced(PYSIDE_INCLUDE_DIR PYSIDE_LIBRARY PYSIDE_BINARY) \ No newline at end of file +mark_as_advanced(PYSIDE_INCLUDE_DIR PYSIDE_LIBRARY PYSIDE_BINARY) From 44917603fa48412a0471d2bba9888367ff83bf24 Mon Sep 17 00:00:00 2001 From: wargio Date: Thu, 11 May 2023 12:59:02 +0800 Subject: [PATCH 237/240] Disable KSyntaxHighlighting on Qt6 --- CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 38f18f17..771bddf1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -140,7 +140,7 @@ if(CUTTER_ENABLE_PYTHON) endif() endif() -if(CUTTER_ENABLE_KSYNTAXHIGHLIGHTING) +if(CUTTER_ENABLE_KSYNTAXHIGHLIGHTING AND (NOT CUTTER_QT6)) if(CUTTER_ENABLE_KSYNTAXHIGHLIGHTING STREQUAL AUTO) find_package(KF5SyntaxHighlighting) if(KF5SyntaxHighlighting_FOUND) @@ -153,6 +153,9 @@ if(CUTTER_ENABLE_KSYNTAXHIGHLIGHTING) set(KSYNTAXHIGHLIGHTING_STATUS ON) endif() else() + if(CUTTER_ENABLE_KSYNTAXHIGHLIGHTING AND CUTTER_QT6) + message(WARNING "KSyntaxHighlighting has been disabled because not supported in QT6") + endif() set(KSYNTAXHIGHLIGHTING_STATUS OFF) endif() From 4742003ff48c677156d76ca394dcbf9da3f96927 Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Tue, 20 Jun 2023 16:40:57 +0800 Subject: [PATCH 238/240] Update rizin & translation submodules (#3194) * Fix plugins paths for windows builds due recent changes in rizin * Disable openssl support for yara win * Disable use_sys_yara in linux/osx/win builds --- dist/CMakeLists.txt | 2 +- dist/bundle_jsdec.ps1 | 7 ++++--- dist/bundle_rz_libswift.ps1 | 6 +++--- dist/bundle_rz_libyara.ps1 | 8 ++++---- dist/bundle_rz_silhouette.ps1 | 6 +++--- rizin | 2 +- scripts/rz-libyara.sh | 2 +- src/CutterApplication.cpp | 13 +++++++------ src/core/Cutter.cpp | 19 +++---------------- src/core/CutterDescriptions.h | 1 - src/translations | 2 +- src/widgets/ComboQuickFilterView.cpp | 2 +- src/widgets/QuickFilterView.cpp | 2 +- 13 files changed, 30 insertions(+), 42 deletions(-) diff --git a/dist/CMakeLists.txt b/dist/CMakeLists.txt index 822942fd..2fe5b671 100644 --- a/dist/CMakeLists.txt +++ b/dist/CMakeLists.txt @@ -7,7 +7,7 @@ unset(RZ_GHIDRA_PREFIX_PATH) if(WIN32) set(CPACK_GENERATOR "ZIP") - set(RIZIN_INSTALL_PLUGDIR "lib/plugins") + set(RIZIN_INSTALL_PLUGDIR "lib/rizin/plugins") if (CUTTER_PACKAGE_DEPENDENCIES) if (CUTTER_ENABLE_PYTHON) diff --git a/dist/bundle_jsdec.ps1 b/dist/bundle_jsdec.ps1 index 762d7b11..d6162346 100644 --- a/dist/bundle_jsdec.ps1 +++ b/dist/bundle_jsdec.ps1 @@ -5,12 +5,13 @@ if (-not (Test-Path -Path 'jsdec' -PathType Container)) { git clone https://github.com/rizinorg/jsdec.git --depth 1 --branch master } cd jsdec -& meson.exe --buildtype=release -Dc_args=-DDUK_USE_DATE_NOW_WINDOWS -Djsc_folder=".." --prefix=$dist p build +& meson.exe --buildtype=release -Dc_args=-DDUK_USE_DATE_NOW_WINDOWS -Djsc_folder=".." --prefix="$dist" p build ninja -C build install $ErrorActionPreference = 'Stop' -$pathdll = "$dist\lib\plugins\core_pdd.dll" +$pathdll = "$dist\lib\rizin\plugins\core_pdd.dll" if(![System.IO.File]::Exists($pathdll)) { type build\meson-logs\meson-log.txt + ls "$dist\lib\rizin\plugins\" throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll)) } -Remove-Item -Recurse -Force $dist\lib\plugins\core_pdd.lib +Remove-Item -Recurse -Force "$dist\lib\rizin\plugins\core_pdd.lib" diff --git a/dist/bundle_rz_libswift.ps1 b/dist/bundle_rz_libswift.ps1 index 9fec607c..9c0b3c32 100644 --- a/dist/bundle_rz_libswift.ps1 +++ b/dist/bundle_rz_libswift.ps1 @@ -7,10 +7,10 @@ if (-not (Test-Path -Path 'libswift' -PathType Container)) { cd libswift & meson.exe --buildtype=release --prefix=$dist build ninja -C build install -$pathdll = "$dist/lib/plugins/swift.dll" +$pathdll = "$dist\lib\rizin\plugins\swift.dll" if(![System.IO.File]::Exists($pathdll)) { type build/meson-logs/meson-log.txt - ls "$dist/lib/plugins/" + ls "$dist\lib\rizin\plugins\" throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll)) } -Remove-Item -Recurse -Force $dist/lib/plugins/swift.lib +Remove-Item -Recurse -Force "$dist\lib\rizin\plugins\swift.lib" diff --git a/dist/bundle_rz_libyara.ps1 b/dist/bundle_rz_libyara.ps1 index c3309b94..984913d6 100644 --- a/dist/bundle_rz_libyara.ps1 +++ b/dist/bundle_rz_libyara.ps1 @@ -8,15 +8,15 @@ if (-not (Test-Path -Path 'rz_libyara' -PathType Container)) { git -C rz_libyara submodule update } cd rz_libyara -& meson.exe --buildtype=release --prefix=$dist build +& meson.exe --buildtype=release --prefix=$dist -Duse_sys_yara=disabled -Denable_openssl=false build ninja -C build install -$pathdll = "$dist/lib/plugins/rz_yara.dll" +$pathdll = "$dist\lib\rizin\plugins\rz_yara.dll" if(![System.IO.File]::Exists($pathdll)) { type build/meson-logs/meson-log.txt - ls "$dist/lib/plugins/" + ls "$dist\lib\rizin\plugins\" throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll)) } -Remove-Item -Recurse -Force $dist/lib/plugins/rz_yara.lib +Remove-Item -Recurse -Force "$dist\lib\rizin\plugins\rz_yara.lib" cd cutter-plugin mkdir build diff --git a/dist/bundle_rz_silhouette.ps1 b/dist/bundle_rz_silhouette.ps1 index 4aeeb2b9..4cf04668 100644 --- a/dist/bundle_rz_silhouette.ps1 +++ b/dist/bundle_rz_silhouette.ps1 @@ -8,10 +8,10 @@ if (-not (Test-Path -Path 'rz-silhouette' -PathType Container)) { cd rz-silhouette & meson.exe --buildtype=release --prefix=$dist build ninja -C build install -$pathdll = "$dist/lib/plugins/rz_silhouette.dll" +$pathdll = "$dist\lib\rizin\plugins\rz_silhouette.dll" if(![System.IO.File]::Exists($pathdll)) { type build/meson-logs/meson-log.txt - ls "$dist/lib/plugins/" + ls "$dist\lib\rizin\plugins\" throw (New-Object System.IO.FileNotFoundException("File not found: $pathdll", $pathdll)) } -Remove-Item -Recurse -Force $dist/lib/plugins/rz_silhouette.lib +Remove-Item -Recurse -Force "$dist\lib\rizin\plugins\rz_silhouette.lib" diff --git a/rizin b/rizin index 9ab709bc..9c6feafd 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 9ab709bc34843f04ffde3b63322c809596123e77 +Subproject commit 9c6feafd4733903fca0cdad50b3bd213ab2b6228 diff --git a/scripts/rz-libyara.sh b/scripts/rz-libyara.sh index f316f2c5..5fdb303c 100755 --- a/scripts/rz-libyara.sh +++ b/scripts/rz-libyara.sh @@ -15,7 +15,7 @@ fi cd rz_libyara -meson --buildtype=release --pkg-config-path="$INSTALL_PREFIX/lib/pkgconfig" --prefix="$INSTALL_PREFIX" build +meson --buildtype=release --pkg-config-path="$INSTALL_PREFIX/lib/pkgconfig" --prefix="$INSTALL_PREFIX" -Duse_sys_yara=disabled build ninja -C build install cd cutter-plugin diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index 6f0612b4..0c758500 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -33,9 +33,9 @@ // has RZ_GITTAP defined and uses it in rz_core_version(). // After that, RZ_GITTAP is not defined anymore and RZ_VERSION is used. #ifdef RZ_GITTAP -#define CUTTER_COMPILE_TIME_RZ_VERSION "" RZ_GITTAP +# define CUTTER_COMPILE_TIME_RZ_VERSION "" RZ_GITTAP #else -#define CUTTER_COMPILE_TIME_RZ_VERSION "" RZ_VERSION +# define CUTTER_COMPILE_TIME_RZ_VERSION "" RZ_VERSION #endif CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc, argv) @@ -162,7 +162,8 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc appdir.cdUp(); // appdir auto sleighHome = appdir; - sleighHome.cd("lib/rizin/plugins/rz_ghidra_sleigh/"); // appdir/lib/rizin/plugins/rz_ghidra_sleigh/ + // appdir/lib/rizin/plugins/rz_ghidra_sleigh/ + sleighHome.cd("lib/rizin/plugins/rz_ghidra_sleigh/"); Core()->setConfig("ghidra.sleighhome", sleighHome.absolutePath()); } #endif @@ -174,8 +175,8 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc rzprefix.cd("Resources"); // Contents/Resources/ auto sleighHome = rzprefix; - sleighHome.cd( - "lib/rizin/plugins/rz_ghidra_sleigh"); // Contents/Resources/lib/rizin/plugins/rz_ghidra_sleigh + // Contents/Resources/lib/rizin/plugins/rz_ghidra_sleigh + sleighHome.cd("lib/rizin/plugins/rz_ghidra_sleigh"); Core()->setConfig("ghidra.sleighhome", sleighHome.absolutePath()); } #endif @@ -183,7 +184,7 @@ CutterApplication::CutterApplication(int &argc, char **argv) : QApplication(argc #if defined(Q_OS_WIN) && defined(CUTTER_ENABLE_PACKAGING) { auto sleighHome = QDir(QCoreApplication::applicationDirPath()); - sleighHome.cd("lib/plugins/rz_ghidra_sleigh"); + sleighHome.cd("lib/rizin/plugins/rz_ghidra_sleigh"); Core()->setConfig("ghidra.sleighhome", sleighHome.absolutePath()); } #endif diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index ebbd2142..db144cb4 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -3084,8 +3084,6 @@ QList CutterCore::getAllImports() RzBinImport *import; RzListIter *iter; bool va = core->io->va || core->bin->is_debugger; - int bin_demangle = getConfigi("bin.demangle"); - int keep_lib = getConfigi("bin.demangle.libs"); CutterRzListForeach (imports, iter, RzBinImport, import) { if (RZ_STR_ISEMPTY(import->name)) { continue; @@ -3099,13 +3097,6 @@ QList CutterCore::getAllImports() if (RZ_STR_ISNOTEMPTY(import->classname)) { name = QString("%1.%2").arg(import->classname, import->name); } - if (bin_demangle) { - char *dname = rz_bin_demangle(bf, NULL, name.toUtf8().constData(), - importDescription.plt, keep_lib); - if (dname) { - name = fromOwnedCharPtr(dname); - } - } if (core->bin->prefix) { name = QString("%1.%2").arg(core->bin->prefix, name); } @@ -3135,7 +3126,6 @@ QList CutterCore::getAllExports() return {}; } - QString lang = getConfigi("bin.demangle") ? getConfig("bin.lang") : ""; bool va = core->io->va || core->bin->is_debugger; QList ret; @@ -3145,7 +3135,7 @@ QList CutterCore::getAllExports() } RzBinSymNames sn = {}; - rz_core_sym_name_init(core, &sn, symbol, lang.isEmpty() ? NULL : lang.toUtf8().constData()); + rz_core_sym_name_init(&sn, symbol); ExportDescription exportDescription; exportDescription.vaddr = rva(bf->o, symbol->paddr, symbol->vaddr, va); @@ -3543,19 +3533,18 @@ QList CutterCore::getAllClassesFromBin() RzListIter *iter, *iter2, *iter3; RzBinClass *c; RzBinSymbol *sym; - RzBinField *f; + RzBinClassField *f; CutterRzListForeach (cs, iter, RzBinClass, c) { BinClassDescription classDescription; classDescription.name = c->name; classDescription.addr = c->addr; - classDescription.index = c->index; CutterRzListForeach (c->methods, iter2, RzBinSymbol, sym) { BinClassMethodDescription methodDescription; methodDescription.name = sym->name; methodDescription.addr = sym->vaddr; classDescription.methods << methodDescription; } - CutterRzListForeach (c->fields, iter3, RzBinField, f) { + CutterRzListForeach (c->fields, iter3, RzBinClassField, f) { BinClassFieldDescription fieldDescription; fieldDescription.name = f->name; fieldDescription.addr = f->vaddr; @@ -3591,7 +3580,6 @@ QList CutterCore::getAllClassesFromFlags() } desc->name = match.captured(1); desc->addr = item.offset; - desc->index = RVA_INVALID; continue; } @@ -3605,7 +3593,6 @@ QList CutterCore::getAllClassesFromFlags() BinClassDescription cls; cls.name = tr("Unknown (%1)").arg(className); cls.addr = RVA_INVALID; - cls.index = 0; ret << cls; classDesc = &ret.last(); classesCache[className] = classDesc; diff --git a/src/core/CutterDescriptions.h b/src/core/CutterDescriptions.h index aed9b508..20a476fc 100644 --- a/src/core/CutterDescriptions.h +++ b/src/core/CutterDescriptions.h @@ -239,7 +239,6 @@ struct BinClassDescription QString name; RVA addr = RVA_INVALID; RVA vtableAddr = RVA_INVALID; - ut64 index = 0; QList baseClasses; QList methods; QList fields; diff --git a/src/translations b/src/translations index e8fc5ca1..5ac7217b 160000 --- a/src/translations +++ b/src/translations @@ -1 +1 @@ -Subproject commit e8fc5ca1acd70fd82a2ac9ac02b0261e57703250 +Subproject commit 5ac7217b12623c7bfd0378380f923cf694ccee22 diff --git a/src/widgets/ComboQuickFilterView.cpp b/src/widgets/ComboQuickFilterView.cpp index a7bcef60..04580584 100644 --- a/src/widgets/ComboQuickFilterView.cpp +++ b/src/widgets/ComboQuickFilterView.cpp @@ -13,7 +13,7 @@ ComboQuickFilterView::ComboQuickFilterView(QWidget *parent) [this]() { emit filterTextChanged(ui->lineEdit->text()); }); connect(ui->lineEdit, &QLineEdit::textChanged, this, - [this](const QString &text) { debounceTimer->start(150); }); + [this]() { debounceTimer->start(150); }); } ComboQuickFilterView::~ComboQuickFilterView() diff --git a/src/widgets/QuickFilterView.cpp b/src/widgets/QuickFilterView.cpp index 1f04c5b9..bf130333 100644 --- a/src/widgets/QuickFilterView.cpp +++ b/src/widgets/QuickFilterView.cpp @@ -16,7 +16,7 @@ QuickFilterView::QuickFilterView(QWidget *parent, bool defaultOn) [this]() { emit filterTextChanged(ui->filterLineEdit->text()); }); connect(ui->filterLineEdit, &QLineEdit::textChanged, this, - [this](const QString &text) { debounceTimer->start(150); }); + [this]() { debounceTimer->start(150); }); if (!defaultOn) { closeFilter(); From 579ac236b6a7f2ae3b86d5270b1f4fb13fabd27d Mon Sep 17 00:00:00 2001 From: wargio Date: Mon, 12 Jun 2023 19:35:02 +0800 Subject: [PATCH 239/240] Implement RzIL statement graph --- src/widgets/RizinGraphWidget.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/widgets/RizinGraphWidget.cpp b/src/widgets/RizinGraphWidget.cpp index b228e4a4..380657ee 100644 --- a/src/widgets/RizinGraphWidget.cpp +++ b/src/widgets/RizinGraphWidget.cpp @@ -27,6 +27,7 @@ RizinGraphWidget::RizinGraphWidget(MainWindow *main) { 'r', tr("References graph (agr)") }, { 'R', tr("Global references graph (agR)") }, { 'x', tr("Cross references graph (agx)") }, + { 'I', tr("RzIL statement graph (agI)") }, { 'g', tr("Custom graph (agg)") }, { ' ', tr("User command") }, }; From cf14fd10066fcd6a3af1cdad30bf3e3ba0c4f0db Mon Sep 17 00:00:00 2001 From: Giovanni <561184+wargio@users.noreply.github.com> Date: Sun, 25 Jun 2023 11:42:23 +0800 Subject: [PATCH 240/240] Add Tools > BaseFind + command line options (#3198) * Add Tools > BaseFind * Rewritten how cutter parses and stores the initial options * Update docs and fixed comments * Add missing endianness option --- docs/source/user-docs/command-line.rst | 38 ++- rizin | 2 +- src/CMakeLists.txt | 11 + src/CutterApplication.cpp | 153 +++++++++++- src/CutterApplication.h | 4 + src/core/Basefind.cpp | 109 ++++++++ src/core/Basefind.h | 47 ++++ src/core/Cutter.cpp | 6 + src/core/Cutter.h | 4 + src/core/CutterDescriptions.h | 14 ++ src/core/MainWindow.cpp | 25 +- src/core/MainWindow.h | 1 + src/core/MainWindow.ui | 12 + src/dialogs/CommentsDialog.cpp | 2 + src/dialogs/InitialOptionsDialog.cpp | 54 +++- src/dialogs/InitialOptionsDialog.h | 2 +- src/tools/basefind/BaseFindDialog.cpp | 97 ++++++++ src/tools/basefind/BaseFindDialog.h | 38 +++ src/tools/basefind/BaseFindDialog.ui | 246 +++++++++++++++++++ src/tools/basefind/BaseFindResultsDialog.cpp | 161 ++++++++++++ src/tools/basefind/BaseFindResultsDialog.h | 68 +++++ src/tools/basefind/BaseFindResultsDialog.ui | 70 ++++++ src/tools/basefind/BaseFindSearchDialog.cpp | 66 +++++ src/tools/basefind/BaseFindSearchDialog.h | 41 ++++ src/tools/basefind/BaseFindSearchDialog.ui | 112 +++++++++ 25 files changed, 1362 insertions(+), 21 deletions(-) create mode 100644 src/core/Basefind.cpp create mode 100644 src/core/Basefind.h create mode 100644 src/tools/basefind/BaseFindDialog.cpp create mode 100644 src/tools/basefind/BaseFindDialog.h create mode 100644 src/tools/basefind/BaseFindDialog.ui create mode 100644 src/tools/basefind/BaseFindResultsDialog.cpp create mode 100644 src/tools/basefind/BaseFindResultsDialog.h create mode 100644 src/tools/basefind/BaseFindResultsDialog.ui create mode 100644 src/tools/basefind/BaseFindSearchDialog.cpp create mode 100644 src/tools/basefind/BaseFindSearchDialog.h create mode 100644 src/tools/basefind/BaseFindSearchDialog.ui diff --git a/docs/source/user-docs/command-line.rst b/docs/source/user-docs/command-line.rst index ceea4d11..39d3904e 100644 --- a/docs/source/user-docs/command-line.rst +++ b/docs/source/user-docs/command-line.rst @@ -40,21 +40,45 @@ Options **2** aaaa (experimental) +.. option:: -a, --arch + + Sets a specific architecture name. + +.. option:: -b, --bits + + Sets a specific architecture bits. + +.. option:: -c, --cpu + + Sets a specific CPU. + +.. option:: -o, --os + + Sets a specific operating system. + +.. option:: -e, --endian + + Sets the endianness (big or little). + .. option:: -F, --format - Force using a specific file format (bin plugin) + Force using a specific file format (bin plugin). .. option:: -B, --base - Load binary at a specific base address + Load binary at a specific base address. + +.. option:: -m, --map + + Map the binary at a specific address. .. option:: -i - Run script file + Run script file. .. option:: -p, --project - Load project file + Load project file. .. option:: -w, --writemode @@ -62,9 +86,13 @@ Options When used together with -A/--analysis , it will open a file directly in write mode without any further dialog or confirmation. +.. option:: -P, --phymode + + Disables virtual addressing. + .. option:: --pythonhome - PYTHONHOME to use for the embedded python interpreter + PYTHONHOME to use for the embedded python interpreter. .. option:: --no-output-redirect diff --git a/rizin b/rizin index 9c6feafd..6bfc67a2 160000 --- a/rizin +++ b/rizin @@ -1 +1 @@ -Subproject commit 9c6feafd4733903fca0cdad50b3bd213ab2b6228 +Subproject commit 6bfc67a2868e07ab89ff931b96dfd3bc65e7371e diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 009b2962..0d433df0 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -6,6 +6,7 @@ set(SOURCES core/Cutter.cpp core/CutterJson.cpp core/RizinCpp.cpp + core/Basefind.cpp dialogs/EditStringDialog.cpp dialogs/WriteCommandsDialogs.cpp widgets/DisassemblerGraphView.cpp @@ -149,6 +150,9 @@ set(SOURCES dialogs/GlibcHeapBinsDialog.cpp widgets/HeapBinsGraphView.cpp dialogs/ArenaInfoDialog.cpp + tools/basefind/BaseFindDialog.cpp + tools/basefind/BaseFindSearchDialog.cpp + tools/basefind/BaseFindResultsDialog.cpp ) set(HEADER_FILES core/Cutter.h @@ -156,6 +160,7 @@ set(HEADER_FILES core/CutterDescriptions.h core/CutterJson.h core/RizinCpp.h + core/Basefind.h dialogs/EditStringDialog.h dialogs/WriteCommandsDialogs.h widgets/DisassemblerGraphView.h @@ -308,6 +313,9 @@ set(HEADER_FILES dialogs/GlibcHeapBinsDialog.h widgets/HeapBinsGraphView.h dialogs/ArenaInfoDialog.h + tools/basefind/BaseFindDialog.h + tools/basefind/BaseFindSearchDialog.h + tools/basefind/BaseFindResultsDialog.h ) set(UI_FILES dialogs/AboutDialog.ui @@ -377,6 +385,9 @@ set(UI_FILES widgets/GlibcHeapWidget.ui dialogs/GlibcHeapBinsDialog.ui dialogs/ArenaInfoDialog.ui + tools/basefind/BaseFindDialog.ui + tools/basefind/BaseFindSearchDialog.ui + tools/basefind/BaseFindResultsDialog.ui ) set(QRC_FILES resources.qrc diff --git a/src/CutterApplication.cpp b/src/CutterApplication.cpp index 0c758500..79a48b59 100644 --- a/src/CutterApplication.cpp +++ b/src/CutterApplication.cpp @@ -296,6 +296,89 @@ bool CutterApplication::loadTranslations() return false; } +QStringList CutterApplication::getArgs() const +{ + auto &options = clOptions.fileOpenOptions; + + QStringList args; + switch (clOptions.analysisLevel) { + case AutomaticAnalysisLevel::None: + args.push_back("-A"); + args.push_back("0"); + break; + case AutomaticAnalysisLevel::AAA: + args.push_back("-A"); + args.push_back("1"); + break; + case AutomaticAnalysisLevel::AAAA: + args.push_back("-A"); + args.push_back("2"); + break; + default: + break; + } + + if (!options.useVA) { + args.push_back("-P"); + } + if (options.writeEnabled) { + args.push_back("-w"); + } + if (!options.script.isEmpty()) { + args.push_back("-i"); + args.push_back(options.script); + } + if (!options.projectFile.isEmpty()) { + args.push_back("-p"); + args.push_back(options.projectFile); + } + if (!options.arch.isEmpty()) { + args.push_back("-a"); + args.push_back(options.arch); + } + if (options.bits > 0) { + args.push_back("-b"); + args.push_back(QString::asprintf("%d", options.bits)); + } + if (!options.cpu.isEmpty()) { + args.push_back("-c"); + args.push_back(options.cpu); + } + if (!options.os.isEmpty()) { + args.push_back("-o"); + args.push_back(options.os); + } + + switch (options.endian) { + case InitialOptions::Endianness::Little: + args.push_back("-e"); + args.push_back("little"); + break; + case InitialOptions::Endianness::Big: + args.push_back("-e"); + args.push_back("big"); + break; + default: + break; + } + if (!options.forceBinPlugin.isEmpty()) { + args.push_back("-F"); + args.push_back(options.forceBinPlugin); + } + if (options.binLoadAddr != RVA_INVALID) { + args.push_back("-B"); + args.push_back(RzAddressString(options.binLoadAddr)); + } + if (options.mapAddr != RVA_INVALID) { + args.push_back("-m"); + args.push_back(RzAddressString(options.mapAddr)); + } + if (!options.filename.isEmpty()) { + args.push_back(options.filename); + } + return args; +} + bool CutterApplication::parseCommandLineOptions() { // Keep this function in sync with documentation @@ -315,6 +398,27 @@ bool CutterApplication::parseCommandLineOptions() QObject::tr("level")); cmd_parser.addOption(analOption); + QCommandLineOption archOption({ "a", "arch" }, QObject::tr("Sets a specific architecture name"), + QObject::tr("arch")); + cmd_parser.addOption(archOption); + + QCommandLineOption bitsOption({ "b", "bits" }, QObject::tr("Sets a specific architecture bits"), + QObject::tr("bits")); + cmd_parser.addOption(bitsOption); + + QCommandLineOption cpuOption({ "c", "cpu" }, QObject::tr("Sets a specific CPU"), + QObject::tr("cpu")); + cmd_parser.addOption(cpuOption); + + QCommandLineOption osOption({ "o", "os" }, QObject::tr("Sets a specific operating system"), + QObject::tr("os")); + cmd_parser.addOption(osOption); + + QCommandLineOption endianOption({ "e", "endian" }, + QObject::tr("Sets the endianness (big or little)"), + QObject::tr("big|little")); + cmd_parser.addOption(endianOption); + QCommandLineOption formatOption({ "F", "format" }, QObject::tr("Force using a specific file format (bin plugin)"), QObject::tr("name")); @@ -325,6 +429,11 @@ bool CutterApplication::parseCommandLineOptions() QObject::tr("base address")); cmd_parser.addOption(baddrOption); + QCommandLineOption maddrOption({ "m", "map" }, + QObject::tr("Map the binary at a specific address"), + QObject::tr("map address")); + cmd_parser.addOption(maddrOption); + QCommandLineOption scriptOption("i", QObject::tr("Run script file"), QObject::tr("file")); cmd_parser.addOption(scriptOption); @@ -336,6 +445,10 @@ bool CutterApplication::parseCommandLineOptions() QObject::tr("Open file in write mode")); cmd_parser.addOption(writeModeOption); + QCommandLineOption phyModeOption({ "P", "phymode" }, + QObject::tr("Disables virtual addressing")); + cmd_parser.addOption(phyModeOption); + QCommandLineOption pythonHomeOption( "pythonhome", QObject::tr("PYTHONHOME to use for embedded python interpreter"), "PYTHONHOME"); @@ -397,15 +510,21 @@ bool CutterApplication::parseCommandLineOptions() return false; } - InitialOptions options; if (!opts.args.isEmpty()) { opts.fileOpenOptions.filename = opts.args[0]; opts.fileOpenOptions.forceBinPlugin = cmd_parser.value(formatOption); if (cmd_parser.isSet(baddrOption)) { - bool ok; + bool ok = false; RVA baddr = cmd_parser.value(baddrOption).toULongLong(&ok, 0); if (ok) { - options.binLoadAddr = baddr; + opts.fileOpenOptions.binLoadAddr = baddr; + } + } + if (cmd_parser.isSet(maddrOption)) { + bool ok = false; + RVA maddr = cmd_parser.value(maddrOption).toULongLong(&ok, 0); + if (ok) { + opts.fileOpenOptions.mapAddr = maddr; } } switch (opts.analysisLevel) { @@ -422,8 +541,36 @@ bool CutterApplication::parseCommandLineOptions() break; } opts.fileOpenOptions.script = cmd_parser.value(scriptOption); + opts.fileOpenOptions.arch = cmd_parser.value(archOption); + opts.fileOpenOptions.cpu = cmd_parser.value(cpuOption); + opts.fileOpenOptions.os = cmd_parser.value(osOption); + if (cmd_parser.isSet(bitsOption)) { + bool ok = false; + int bits = cmd_parser.value(bitsOption).toInt(&ok, 10); + if (ok && bits > 0) { + opts.fileOpenOptions.bits = bits; + } + } + if (cmd_parser.isSet(endianOption)) { + QString endian = cmd_parser.value(endianOption).toLower(); + opts.fileOpenOptions.endian = InitialOptions::Endianness::Auto; + if (endian == "little") { + opts.fileOpenOptions.endian = InitialOptions::Endianness::Little; + } else if (endian == "big") { + opts.fileOpenOptions.endian = InitialOptions::Endianness::Big; + } else { + fprintf(stderr, "%s\n", + QObject::tr("Invalid Endianness. You can only set it to `big` or `little`.") + .toLocal8Bit() + .constData()); + return false; + } + } else { + opts.fileOpenOptions.endian = InitialOptions::Endianness::Auto; + } opts.fileOpenOptions.writeEnabled = cmd_parser.isSet(writeModeOption); + opts.fileOpenOptions.useVA = !cmd_parser.isSet(phyModeOption); } opts.fileOpenOptions.projectFile = cmd_parser.value(projectOption); diff --git a/src/CutterApplication.h b/src/CutterApplication.h index cd27a26a..e4ed041c 100644 --- a/src/CutterApplication.h +++ b/src/CutterApplication.h @@ -33,6 +33,10 @@ public: void launchNewInstance(const QStringList &args = {}); + InitialOptions getInitialOptions() const { return clOptions.fileOpenOptions; } + void setInitialOptions(const InitialOptions &options) { clOptions.fileOpenOptions = options; } + QStringList getArgs() const; + protected: bool event(QEvent *e); diff --git a/src/core/Basefind.cpp b/src/core/Basefind.cpp new file mode 100644 index 00000000..8cc39035 --- /dev/null +++ b/src/core/Basefind.cpp @@ -0,0 +1,109 @@ +#include "Basefind.h" + +bool Basefind::threadCallback(const RzBaseFindThreadInfo *info, void *user) +{ + auto th = reinterpret_cast(user); + return th->updateProgress(info); +} + +Basefind::Basefind(CutterCore *core) + : core(core), + scores(nullptr), + continue_run(true) +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) + , + mutex(QMutex::Recursive) +#endif +{ + memset(&options, 0, sizeof(RzBaseFindOpt)); +} + +Basefind::~Basefind() +{ + cancel(); + wait(); + rz_list_free(scores); +} + +bool Basefind::setOptions(const RzBaseFindOpt *opts) +{ + mutex.lock(); + options.max_threads = opts->max_threads; + options.pointer_size = opts->pointer_size; + options.start_address = opts->start_address; + options.end_address = opts->end_address; + options.alignment = opts->alignment; + options.min_score = opts->min_score; + options.min_string_len = opts->min_string_len; + mutex.unlock(); + + if (options.start_address >= options.end_address) { + qWarning() << "Start address is >= end address"; + return false; + } else if (options.alignment < RZ_BASEFIND_BASE_ALIGNMENT) { + qWarning() << "Alignment must be at least " + << QString::asprintf("0x%x", RZ_BASEFIND_BASE_ALIGNMENT); + return false; + } else if (options.min_score < 1) { + qWarning() << "Min score must be at least 1"; + return false; + } else if (options.min_string_len < 1) { + qWarning() << "Min string length must be at least 1"; + return false; + } + return true; +} + +void Basefind::run() +{ + qRegisterMetaType(); + + mutex.lock(); + rz_list_free(scores); + scores = nullptr; + continue_run = true; + mutex.unlock(); + + core->coreMutex.lock(); + options.callback = threadCallback; + options.user = this; + scores = rz_basefind(core->core_, &options); + core->coreMutex.unlock(); + + emit complete(); +} + +void Basefind::cancel() +{ + mutex.lock(); + continue_run = false; + mutex.unlock(); +} + +QList Basefind::results() +{ + QList pairs; + RzListIter *it; + RzBaseFindScore *pair; + CutterRzListForeach (scores, it, RzBaseFindScore, pair) { + BasefindResultDescription desc; + desc.candidate = pair->candidate; + desc.score = pair->score; + pairs.push_back(desc); + } + return pairs; +} + +bool Basefind::updateProgress(const RzBaseFindThreadInfo *info) +{ + mutex.lock(); + + BasefindCoreStatusDescription status; + status.index = info->thread_idx; + status.percentage = info->percentage; + + emit progress(status); + bool ret = continue_run; + mutex.unlock(); + return ret; +} diff --git a/src/core/Basefind.h b/src/core/Basefind.h new file mode 100644 index 00000000..ded42fd1 --- /dev/null +++ b/src/core/Basefind.h @@ -0,0 +1,47 @@ +#ifndef CUTTER_BASEFIND_CORE_H +#define CUTTER_BASEFIND_CORE_H + +#include +#include + +#include "Cutter.h" +#include "CutterDescriptions.h" +#include + +class CutterCore; + +class Basefind : public QThread +{ + Q_OBJECT + +public: + explicit Basefind(CutterCore *core); + virtual ~Basefind(); + + void run(); + bool setOptions(const RzBaseFindOpt *opts); + QList results(); + +public slots: + void cancel(); + +signals: + void progress(BasefindCoreStatusDescription status); + void complete(); + +private: + CutterCore *const core; + RzList *scores; + bool continue_run; + RzBaseFindOpt options; +#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) + QMutex mutex; +#else + QRecursiveMutex mutex; +#endif + + bool updateProgress(const RzBaseFindThreadInfo *info); + static bool threadCallback(const RzBaseFindThreadInfo *info, void *user); +}; + +#endif // CUTTER_BASEFIND_CORE_H diff --git a/src/core/Cutter.cpp b/src/core/Cutter.cpp index db144cb4..4e8f06f4 100644 --- a/src/core/Cutter.cpp +++ b/src/core/Cutter.cpp @@ -4577,3 +4577,9 @@ void CutterCore::writeGraphvizGraphToFile(QString path, QString format, RzCoreGr } } } + +bool CutterCore::rebaseBin(RVA base_address) +{ + CORE_LOCK(); + return rz_core_bin_rebase(core, base_address); +} diff --git a/src/core/Cutter.h b/src/core/Cutter.h index dd9e67c8..14fbfde7 100644 --- a/src/core/Cutter.h +++ b/src/core/Cutter.h @@ -4,6 +4,7 @@ #include "core/CutterCommon.h" #include "core/CutterDescriptions.h" #include "core/CutterJson.h" +#include "core/Basefind.h" #include "common/BasicInstructionHighlighter.h" #include @@ -69,6 +70,7 @@ class CUTTER_EXPORT CutterCore : public QObject friend class RzCoreLocked; friend class RizinTask; + friend class Basefind; public: explicit CutterCore(QObject *parent = nullptr); @@ -556,6 +558,8 @@ public: void setGraphEmpty(bool empty); bool isGraphEmpty(); + bool rebaseBin(RVA base_address); + void getRegs(); QList regs; void setSettings(); diff --git a/src/core/CutterDescriptions.h b/src/core/CutterDescriptions.h index 20a476fc..5f311be5 100644 --- a/src/core/CutterDescriptions.h +++ b/src/core/CutterDescriptions.h @@ -385,6 +385,18 @@ struct Arena ut64 max_system_mem; }; +struct BasefindCoreStatusDescription +{ + size_t index; + ut32 percentage; +}; + +struct BasefindResultDescription +{ + RVA candidate; + ut32 score; +}; + Q_DECLARE_METATYPE(FunctionDescription) Q_DECLARE_METATYPE(ImportDescription) Q_DECLARE_METATYPE(ExportDescription) @@ -423,5 +435,7 @@ Q_DECLARE_METATYPE(BreakpointDescription::PositionType) Q_DECLARE_METATYPE(ProcessDescription) Q_DECLARE_METATYPE(RefDescription) Q_DECLARE_METATYPE(VariableDescription) +Q_DECLARE_METATYPE(BasefindCoreStatusDescription) +Q_DECLARE_METATYPE(BasefindResultDescription) #endif // DESCRIPTIONS_H diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index e873b0d7..8a6edf24 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -115,6 +115,9 @@ #include #include +// Tools +#include "tools/basefind/BaseFindDialog.h" + #define PROJECT_FILE_FILTER tr("Rizin Project (*.rzdb)") template @@ -1087,11 +1090,11 @@ MemoryDockWidget *MainWindow::addNewMemoryWidget(MemoryWidgetType type, RVA addr memoryWidget = new DecompilerWidget(this); break; case MemoryWidgetType::CallGraph: - memoryWidget = new CallGraphWidget(this, false); - break; + memoryWidget = new CallGraphWidget(this, false); + break; case MemoryWidgetType::GlobalCallGraph: - memoryWidget = new CallGraphWidget(this, true); - break; + memoryWidget = new CallGraphWidget(this, true); + break; } auto seekable = memoryWidget->getSeekable(); seekable->setSynchronization(synchronized); @@ -1637,6 +1640,12 @@ void MainWindow::on_actionTabs_triggered() setTabLocation(); } +void MainWindow::on_actionBaseFind_triggered() +{ + auto dialog = new BaseFindDialog(this); + dialog->show(); +} + void MainWindow::on_actionAbout_triggered() { AboutDialog *a = new AboutDialog(this); @@ -1774,12 +1783,10 @@ void MainWindow::on_actionExport_as_code_triggered() return; } - - 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)); + dialog.selectedNameFilter() != instructionsInComments + ? rz_lang_byte_array(buffer.data(), size, typMap[dialog.selectedNameFilter()]) + : rz_core_print_bytes_with_inst(rc, buffer.data(), 0, size)); fileOut << string.get(); } diff --git a/src/core/MainWindow.h b/src/core/MainWindow.h index ce1bdceb..733e7ea5 100644 --- a/src/core/MainWindow.h +++ b/src/core/MainWindow.h @@ -152,6 +152,7 @@ public slots: void toggleOverview(bool visibility, GraphWidget *targetGraph); private slots: + void on_actionBaseFind_triggered(); void on_actionAbout_triggered(); void on_actionIssue_triggered(); void documentationClicked(); diff --git a/src/core/MainWindow.ui b/src/core/MainWindow.ui index 2af046cc..0cf17945 100644 --- a/src/core/MainWindow.ui +++ b/src/core/MainWindow.ui @@ -128,6 +128,12 @@ + + + Tools + + + Help @@ -184,6 +190,7 @@ + @@ -233,6 +240,11 @@ Zen mode + + + BaseFind + + About diff --git a/src/dialogs/CommentsDialog.cpp b/src/dialogs/CommentsDialog.cpp index f5cc1544..4d362d4f 100644 --- a/src/dialogs/CommentsDialog.cpp +++ b/src/dialogs/CommentsDialog.cpp @@ -1,6 +1,8 @@ #include "CommentsDialog.h" #include "ui_CommentsDialog.h" +#include + #include "core/Cutter.h" CommentsDialog::CommentsDialog(QWidget *parent) : QDialog(parent), ui(new Ui::CommentsDialog) diff --git a/src/dialogs/InitialOptionsDialog.cpp b/src/dialogs/InitialOptionsDialog.cpp index 94e43f89..06157cc8 100644 --- a/src/dialogs/InitialOptionsDialog.cpp +++ b/src/dialogs/InitialOptionsDialog.cpp @@ -14,6 +14,7 @@ #include "core/Cutter.h" #include "common/AnalysisTask.h" +#include "CutterApplication.h" InitialOptionsDialog::InitialOptionsDialog(MainWindow *main) : QDialog(nullptr), // parent must not be main @@ -179,9 +180,56 @@ void InitialOptionsDialog::loadOptions(const InitialOptions &options) ui->entry_loadOffset->setText(RzAddressString(options.binLoadAddr)); } + if (options.mapAddr != RVA_INVALID) { + ui->entry_mapOffset->setText(RzAddressString(options.mapAddr)); + } + + ui->vaCheckBox->setChecked(options.useVA); ui->writeCheckBox->setChecked(options.writeEnabled); - // TODO: all other options should also be applied to the ui + if (!options.arch.isNull() && !options.arch.isEmpty()) { + ui->archComboBox->setCurrentText(options.arch); + } + + if (!options.cpu.isNull() && !options.cpu.isEmpty()) { + ui->cpuComboBox->setCurrentText(options.cpu); + } + + if (options.bits > 0) { + ui->bitsComboBox->setCurrentText(QString::asprintf("%d", options.bits)); + } + + if (!options.os.isNull() && !options.os.isEmpty()) { + ui->kernelComboBox->setCurrentText(options.os); + } + + if (!options.forceBinPlugin.isNull() && !options.forceBinPlugin.isEmpty()) { + ui->formatComboBox->setCurrentText(options.forceBinPlugin); + } + + if (!options.loadBinInfo) { + ui->binCheckBox->setChecked(false); + } + + ui->writeCheckBox->setChecked(options.writeEnabled); + + switch (options.endian) { + case InitialOptions::Endianness::Little: + ui->endiannessComboBox->setCurrentIndex(1); + break; + case InitialOptions::Endianness::Big: + ui->endiannessComboBox->setCurrentIndex(2); + break; + default: + break; + } + + ui->demangleCheckBox->setChecked(options.demangle); + + if (!options.pdbFile.isNull() && !options.pdbFile.isEmpty()) { + ui->pdbCheckBox->setChecked(true); + ui->pdbLineEdit->setText(options.pdbFile); + } } void InitialOptionsDialog::setTooltipWithConfigHelp(QWidget *w, const char *config) @@ -246,7 +294,7 @@ QList InitialOptionsDialog::getSelectedAdvancedAnalCmds() co return advanced; } -void InitialOptionsDialog::setupAndStartAnalysis(/*int level, QList advanced*/) +void InitialOptionsDialog::setupAndStartAnalysis() { InitialOptions options; @@ -322,6 +370,8 @@ void InitialOptionsDialog::setupAndStartAnalysis(/*int level, QList adv Core()->getAsyncTaskManager()->start(analysisTaskPtr); done(0); + + static_cast(qApp)->setInitialOptions(options); } void InitialOptionsDialog::on_okButton_clicked() diff --git a/src/dialogs/InitialOptionsDialog.h b/src/dialogs/InitialOptionsDialog.h index 90de4394..74a80a7f 100644 --- a/src/dialogs/InitialOptionsDialog.h +++ b/src/dialogs/InitialOptionsDialog.h @@ -20,7 +20,7 @@ public: explicit InitialOptionsDialog(MainWindow *main); ~InitialOptionsDialog(); - void setupAndStartAnalysis(/*int level, QList advanced*/); + void setupAndStartAnalysis(); private slots: void on_okButton_clicked(); diff --git a/src/tools/basefind/BaseFindDialog.cpp b/src/tools/basefind/BaseFindDialog.cpp new file mode 100644 index 00000000..17adc133 --- /dev/null +++ b/src/tools/basefind/BaseFindDialog.cpp @@ -0,0 +1,97 @@ +#include "BaseFindDialog.h" +#include "ui_BaseFindDialog.h" + +#include "BaseFindSearchDialog.h" + +#include +#include + +BaseFindDialog::BaseFindDialog(QWidget *parent) : QDialog(parent), ui(new Ui::BaseFindDialog) +{ + ui->setupUi(this); + setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint)); + + // Fill in N-thread Combo + size_t n_cores = rz_th_physical_core_number(); + ui->nCoresCombo->clear(); + for (size_t i = n_cores; i > 0; i--) { + if (n_cores == i) { + ui->nCoresCombo->addItem("All Cores"); + continue; + } + ui->nCoresCombo->addItem(QString::number(i)); + } + + ui->startAddressEdit->setText(Core()->getConfig("basefind.search.start")); + ui->endAddressEdit->setText(Core()->getConfig("basefind.search.end")); + ui->alignmentEdit->setText(Core()->getConfig("basefind.alignment")); + ui->minStrLenEdit->setValue(Core()->getConfigut64("basefind.min.string")); + ui->minScoreEdit->setValue(Core()->getConfigut64("basefind.min.score")); + + size_t selected_n_cores = Core()->getConfigut64("basefind.max.threads"); + if (selected_n_cores < n_cores && selected_n_cores > 0) { + ui->nCoresCombo->setCurrentIndex(n_cores - selected_n_cores); + } +} + +BaseFindDialog::~BaseFindDialog() {} + +size_t BaseFindDialog::getNCores() const +{ + size_t n_cores = rz_th_physical_core_number(); + return n_cores - ui->nCoresCombo->currentIndex(); +} + +ut32 BaseFindDialog::getPointerSize() const +{ + auto index = ui->pointerSizeCombo->currentIndex(); + QString value = ui->pointerSizeCombo->itemText(index); + return value.toULong(nullptr, 0); +} + +RVA BaseFindDialog::getStartAddress() const +{ + QString value = ui->startAddressEdit->text(); + return value.toULongLong(nullptr, 0); +} + +RVA BaseFindDialog::getEndAddress() const +{ + QString value = ui->endAddressEdit->text(); + return value.toULongLong(nullptr, 0); +} + +RVA BaseFindDialog::getAlignment() const +{ + QString value = ui->alignmentEdit->text(); + return value.toULongLong(nullptr, 0); +} + +ut32 BaseFindDialog::getMinStrLen() const +{ + return ui->minStrLenEdit->value(); +} + +ut32 BaseFindDialog::getMinScore() const +{ + return ui->minScoreEdit->value(); +} + +void BaseFindDialog::on_buttonBox_accepted() +{ + RzBaseFindOpt options = {}; + options.max_threads = getNCores(); + options.pointer_size = getPointerSize(); + options.start_address = getStartAddress(); + options.end_address = getEndAddress(); + options.alignment = getAlignment(); + options.min_score = getMinScore(); + options.min_string_len = getMinStrLen(); + options.callback = nullptr; + options.user = nullptr; + + BaseFindSearchDialog *bfs = new BaseFindSearchDialog(parentWidget()); + bfs->show(&options); +} + +void BaseFindDialog::on_buttonBox_rejected() {} diff --git a/src/tools/basefind/BaseFindDialog.h b/src/tools/basefind/BaseFindDialog.h new file mode 100644 index 00000000..3142eb88 --- /dev/null +++ b/src/tools/basefind/BaseFindDialog.h @@ -0,0 +1,38 @@ +#ifndef BASEFIND_DIALOG_H +#define BASEFIND_DIALOG_H + +#include +#include +#include + +#include + +namespace Ui { +class BaseFindDialog; +} + +class BaseFindDialog : public QDialog +{ + Q_OBJECT + +public: + explicit BaseFindDialog(QWidget *parent = nullptr); + ~BaseFindDialog(); + + size_t getNCores() const; + ut32 getPointerSize() const; + RVA getStartAddress() const; + RVA getEndAddress() const; + RVA getAlignment() const; + ut32 getMinStrLen() const; + ut32 getMinScore() const; + +private slots: + void on_buttonBox_accepted(); + void on_buttonBox_rejected(); + +private: + std::unique_ptr ui; +}; + +#endif // BASEFIND_DIALOG_H diff --git a/src/tools/basefind/BaseFindDialog.ui b/src/tools/basefind/BaseFindDialog.ui new file mode 100644 index 00000000..1f3fd2d4 --- /dev/null +++ b/src/tools/basefind/BaseFindDialog.ui @@ -0,0 +1,246 @@ + + + BaseFindDialog + + + Qt::NonModal + + + + 0 + 0 + 373 + 348 + + + + + 0 + 0 + + + + BaseFind + + + + QLayout::SetMinimumSize + + + + + QLayout::SetMinimumSize + + + + + + 0 + 0 + + + + Cores: + + + + + + + + + + + 0 + 0 + + + + Pointer Size: + + + + + + + + 32 + + + + + 64 + + + + + + + + Start Address: + + + + + + + + 382 + 16777215 + + + + + + + + + + + End Address: + + + + + + + + 382 + 16777215 + + + + + + + + Alignment: + + + + + + + + 382 + 16777215 + + + + + + + + Min String Length: + + + + + + + + 382 + 16777215 + + + + 4 + + + 999999999 + + + + + + + Min Score: + + + + + + + + 382 + 16777215 + + + + 1 + + + 999999999 + + + + + + + + + QLayout::SetMinimumSize + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + Remove item + + + + + Remove all + + + Remove all + + + + + + + buttonBox + accepted() + BaseFindDialog + accept() + + + 248 + 234 + + + 157 + 274 + + + + + buttonBox + rejected() + BaseFindDialog + reject() + + + 316 + 240 + + + 286 + 254 + + + + + diff --git a/src/tools/basefind/BaseFindResultsDialog.cpp b/src/tools/basefind/BaseFindResultsDialog.cpp new file mode 100644 index 00000000..993031b4 --- /dev/null +++ b/src/tools/basefind/BaseFindResultsDialog.cpp @@ -0,0 +1,161 @@ +#include "BaseFindResultsDialog.h" +#include "ui_BaseFindResultsDialog.h" + +#include +#include + +#include +#include + +BaseFindResultsModel::BaseFindResultsModel(QList *list, QObject *parent) + : QAbstractListModel(parent), list(list) +{ +} + +int BaseFindResultsModel::rowCount(const QModelIndex &) const +{ + return list->count(); +} + +int BaseFindResultsModel::columnCount(const QModelIndex &) const +{ + return BaseFindResultsModel::ColumnCount; +} + +QVariant BaseFindResultsModel::data(const QModelIndex &index, int role) const +{ + if (index.row() >= list->count()) + return QVariant(); + + const BasefindResultDescription &entry = list->at(index.row()); + + switch (role) { + case Qt::DisplayRole: + switch (index.column()) { + case ScoreColumn: + return QString::asprintf("%u", entry.score); + case CandidateColumn: + return QString::asprintf("%#010llx", entry.candidate); + default: + return QVariant(); + } + + case Qt::ToolTipRole: { + return QString::asprintf("%#010llx", entry.candidate); + } + + default: + return QVariant(); + } +} + +QVariant BaseFindResultsModel::headerData(int section, Qt::Orientation, int role) const +{ + switch (role) { + case Qt::DisplayRole: + switch (section) { + case ScoreColumn: + return tr("Score"); + case CandidateColumn: + return tr("Address"); + default: + return QVariant(); + } + default: + return QVariant(); + } +} + +BaseFindResultsDialog::BaseFindResultsDialog(QList results, + QWidget *parent) + : QDialog(parent), list(results), ui(new Ui::BaseFindResultsDialog) +{ + ui->setupUi(this); + setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint)); + + model = new BaseFindResultsModel(&list, this); + ui->tableView->setModel(model); + ui->tableView->sortByColumn(BaseFindResultsModel::ScoreColumn, Qt::AscendingOrder); + ui->tableView->verticalHeader()->hide(); + ui->tableView->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); + ui->tableView->setContextMenuPolicy(Qt::CustomContextMenu); + + blockMenu = new QMenu(this); + actionCopyCandidate = new QAction(tr("Copy %1"), this); + actionSetLoadAddr = new QAction(tr("Reopen Cutter with base address as %1"), this); + actionSetMapAddr = new QAction(tr("Reopen Cutter with map address as %1"), this); + + connect(ui->tableView, &QWidget::customContextMenuRequested, this, + &BaseFindResultsDialog::showItemContextMenu); + connect(actionCopyCandidate, &QAction::triggered, this, + &BaseFindResultsDialog::onActionCopyLine); + connect(actionSetLoadAddr, &QAction::triggered, this, + &BaseFindResultsDialog::onActionSetLoadAddr); + connect(actionSetMapAddr, &QAction::triggered, this, + &BaseFindResultsDialog::onActionSetMapAddr); + + blockMenu->addAction(actionSetLoadAddr); + blockMenu->addAction(actionSetMapAddr); + blockMenu->addAction(actionCopyCandidate); + addActions(blockMenu->actions()); +} + +void BaseFindResultsDialog::showItemContextMenu(const QPoint &pt) +{ + auto index = ui->tableView->currentIndex(); + if (index.isValid()) { + const BasefindResultDescription &entry = list.at(index.row()); + candidate = entry.candidate; + auto addr = QString::asprintf("%#010llx", candidate); + actionCopyCandidate->setText(tr("Copy %1").arg(addr)); + actionSetLoadAddr->setText(tr("Reopen Cutter with base address as %1").arg(addr)); + actionSetMapAddr->setText(tr("Reopen Cutter with map address as %1").arg(addr)); + blockMenu->exec(this->mapToGlobal(pt)); + } +} + +void BaseFindResultsDialog::onActionCopyLine() +{ + auto clipboard = QApplication::clipboard(); + clipboard->setText(QString::asprintf("%#010llx", candidate)); +} + +void BaseFindResultsDialog::onActionSetLoadAddr() +{ + auto cutter = static_cast(qApp); + auto options = cutter->getInitialOptions(); + auto oldValue = options.binLoadAddr; + + // override options to generate correct args + options.binLoadAddr = candidate; + cutter->setInitialOptions(options); + auto args = cutter->getArgs(); + + // revert back options + options.binLoadAddr = oldValue; + cutter->setInitialOptions(options); + + cutter->launchNewInstance(args); +} + +void BaseFindResultsDialog::onActionSetMapAddr() +{ + auto cutter = static_cast(qApp); + auto options = cutter->getInitialOptions(); + auto oldValue = options.mapAddr; + + // override options to generate correct args + options.mapAddr = candidate; + cutter->setInitialOptions(options); + auto args = cutter->getArgs(); + + // revert back options + options.mapAddr = oldValue; + cutter->setInitialOptions(options); + + cutter->launchNewInstance(args); +} + +BaseFindResultsDialog::~BaseFindResultsDialog() {} + +void BaseFindResultsDialog::on_buttonBox_rejected() {} diff --git a/src/tools/basefind/BaseFindResultsDialog.h b/src/tools/basefind/BaseFindResultsDialog.h new file mode 100644 index 00000000..2d9367eb --- /dev/null +++ b/src/tools/basefind/BaseFindResultsDialog.h @@ -0,0 +1,68 @@ +#ifndef BASEFIND_RESULTS_DIALOG_H +#define BASEFIND_RESULTS_DIALOG_H + +#include +#include +#include +#include + +#include + +class BaseFindResultsDialog; + +namespace Ui { +class BaseFindResultsDialog; +} + +class BaseFindResultsModel : public QAbstractListModel +{ + Q_OBJECT + + friend BaseFindResultsDialog; + +public: + enum Column { ScoreColumn = 0, CandidateColumn, ColumnCount }; + + BaseFindResultsModel(QList *list, QObject *parent = nullptr); + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const; + + int rowCount(const QModelIndex &parent = QModelIndex()) const; + int columnCount(const QModelIndex &parent = QModelIndex()) const; + +private: + QList *list; +}; + +class BaseFindResultsDialog : public QDialog +{ + Q_OBJECT + +public: + explicit BaseFindResultsDialog(QList results, + QWidget *parent = nullptr); + ~BaseFindResultsDialog(); + +public slots: + void showItemContextMenu(const QPoint &pt); + +private slots: + void on_buttonBox_rejected(); + +private: + void onActionCopyLine(); + void onActionSetLoadAddr(); + void onActionSetMapAddr(); + + QList list; + std::unique_ptr ui; + BaseFindResultsModel *model; + QMenu *blockMenu; + QAction *actionCopyCandidate; + QAction *actionSetLoadAddr; + QAction *actionSetMapAddr; + RVA candidate; +}; + +#endif // BASEFIND_RESULTS_DIALOG_H diff --git a/src/tools/basefind/BaseFindResultsDialog.ui b/src/tools/basefind/BaseFindResultsDialog.ui new file mode 100644 index 00000000..543082d0 --- /dev/null +++ b/src/tools/basefind/BaseFindResultsDialog.ui @@ -0,0 +1,70 @@ + + + BaseFindResultsDialog + + + Qt::NonModal + + + + 0 + 0 + 582 + 382 + + + + + 0 + 0 + + + + BaseFind Results + + + + QLayout::SetMinimumSize + + + + + QLayout::SetMinimumSize + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Close + + + + + + + + + + + buttonBox + rejected() + BaseFindResultsDialog + reject() + + + 316 + 240 + + + 286 + 254 + + + + + diff --git a/src/tools/basefind/BaseFindSearchDialog.cpp b/src/tools/basefind/BaseFindSearchDialog.cpp new file mode 100644 index 00000000..bc29af4f --- /dev/null +++ b/src/tools/basefind/BaseFindSearchDialog.cpp @@ -0,0 +1,66 @@ +#include "BaseFindSearchDialog.h" +#include "ui_BaseFindSearchDialog.h" + +#include "BaseFindResultsDialog.h" + +#include +#include + +#include +#include + +BaseFindSearchDialog::BaseFindSearchDialog(QWidget *parent) + : QDialog(parent), basefind(new Basefind(Core())), ui(new Ui::BaseFindSearchDialog) +{ + ui->setupUi(this); + setWindowFlags(windowFlags() & (~Qt::WindowContextHelpButtonHint)); +} + +BaseFindSearchDialog::~BaseFindSearchDialog() {} + +void BaseFindSearchDialog::show(RzBaseFindOpt *opts) +{ + size_t n_cores = rz_th_physical_core_number(); + if (opts->max_threads > n_cores || opts->max_threads < 1) { + opts->max_threads = n_cores; + } + + QFormLayout *layout = new QFormLayout(); + ui->scrollAreaWidgetContents->setLayout(layout); + for (ut32 i = 0; i < opts->max_threads; ++i) { + QString label = QString::asprintf("Core %u", i); + QProgressBar *pbar = new QProgressBar(nullptr); + layout->addRow(label, pbar); + pbar->setRange(0, 100); + bars.push_back(pbar); + } + + if (!basefind->setOptions(opts)) { + return; + } + + connect(this, &BaseFindSearchDialog::cancelSearch, basefind.get(), &Basefind::cancel); + connect(basefind.get(), &Basefind::progress, this, &BaseFindSearchDialog::onProgress); + connect(basefind.get(), &Basefind::complete, this, &BaseFindSearchDialog::onCompletion); + + basefind->start(); + this->QDialog::show(); +} + +void BaseFindSearchDialog::onProgress(BasefindCoreStatusDescription status) +{ + bars[status.index]->setValue(status.percentage); +} + +void BaseFindSearchDialog::onCompletion() +{ + auto results = basefind->results(); + BaseFindResultsDialog *table = new BaseFindResultsDialog(results, parentWidget()); + table->show(); + this->close(); +} + +void BaseFindSearchDialog::on_buttonBox_rejected() +{ + emit cancelSearch(); +} diff --git a/src/tools/basefind/BaseFindSearchDialog.h b/src/tools/basefind/BaseFindSearchDialog.h new file mode 100644 index 00000000..bd59d6cb --- /dev/null +++ b/src/tools/basefind/BaseFindSearchDialog.h @@ -0,0 +1,41 @@ +#ifndef BASEFIND_SEARCH_DIALOG_H +#define BASEFIND_SEARCH_DIALOG_H + +#include +#include +#include +#include + +#include + +namespace Ui { +class BaseFindSearchDialog; +} + +class BaseFindSearchDialog : public QDialog +{ + Q_OBJECT + +public: + explicit BaseFindSearchDialog(QWidget *parent = nullptr); + ~BaseFindSearchDialog(); + + void show(RzBaseFindOpt *opts); + +public slots: + void onProgress(BasefindCoreStatusDescription status); + void onCompletion(); + +signals: + void cancelSearch(); + +private slots: + void on_buttonBox_rejected(); + +private: + std::vector bars; + std::unique_ptr basefind; + std::unique_ptr ui; +}; + +#endif // BASEFIND_SEARCH_DIALOG_H diff --git a/src/tools/basefind/BaseFindSearchDialog.ui b/src/tools/basefind/BaseFindSearchDialog.ui new file mode 100644 index 00000000..053cd78d --- /dev/null +++ b/src/tools/basefind/BaseFindSearchDialog.ui @@ -0,0 +1,112 @@ + + + BaseFindSearchDialog + + + Qt::NonModal + + + + 0 + 0 + 582 + 382 + + + + + 0 + 0 + + + + Searching for base address + + + + QLayout::SetMinimumSize + + + + + QLayout::SetMinimumSize + + + + + + 0 + 0 + + + + QAbstractScrollArea::AdjustToContents + + + true + + + + + 0 + 0 + 564 + 320 + + + + + 0 + 0 + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel + + + + + + + + + Remove item + + + + + Remove all + + + Remove all + + + + + + + buttonBox + rejected() + BaseFindSearchDialog + reject() + + + 316 + 240 + + + 286 + 254 + + + + +