From 37e4416dd2c003dd121a521b4198ae53a56fbde4 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Mon, 17 Jul 2023 15:45:23 +0800 Subject: [PATCH] temporary --- src/gui/Src/BasicView/HexDump.cpp | 7 +- src/gui/Src/BasicView/HexDump.h | 2 +- src/gui/Src/Memory/MemoryPage.h | 6 +- src/gui/Src/Tracer/TraceDump.cpp | 1575 ++++++++++++++++++++++++ src/gui/Src/Tracer/TraceDump.h | 128 ++ src/gui/Src/Tracer/TraceFileDump.cpp | 40 +- src/gui/Src/Tracer/TraceFileDump.h | 16 + src/gui/Src/Tracer/TraceFileReader.cpp | 5 + src/gui/Src/Tracer/TraceFileReader.h | 1 + src/gui/Src/Tracer/TraceWidget.cpp | 14 +- src/gui/Src/Tracer/TraceWidget.h | 4 + src/gui/Src/Tracer/TraceWidget.ui | 190 +-- src/gui/x64dbg.pro | 2 + 13 files changed, 1896 insertions(+), 94 deletions(-) create mode 100644 src/gui/Src/Tracer/TraceDump.cpp create mode 100644 src/gui/Src/Tracer/TraceDump.h diff --git a/src/gui/Src/BasicView/HexDump.cpp b/src/gui/Src/BasicView/HexDump.cpp index 9505e192..cc31789b 100644 --- a/src/gui/Src/BasicView/HexDump.cpp +++ b/src/gui/Src/BasicView/HexDump.cpp @@ -11,7 +11,7 @@ static int dwordStringMaxLength(HexDump::DwordViewMode mode); static int qwordStringMaxLength(HexDump::QwordViewMode mode); static int twordStringMaxLength(HexDump::TwordViewMode mode); -HexDump::HexDump(QWidget* parent) +HexDump::HexDump(QWidget* parent, MemoryPage* memPage) : AbstractTableView(parent) { memset(&mSelection, 0, sizeof(SelectionData)); @@ -22,7 +22,10 @@ HexDump::HexDump(QWidget* parent) setRowCount(0); - mMemPage = new MemoryPage(0, 0); + if(!memPage) + mMemPage = new MemoryPage(0, 0, this); + else + mMemPage = memPage; mForceColumn = -1; clearDescriptors(); diff --git a/src/gui/Src/BasicView/HexDump.h b/src/gui/Src/BasicView/HexDump.h index bc428c10..4f403cde 100644 --- a/src/gui/Src/BasicView/HexDump.h +++ b/src/gui/Src/BasicView/HexDump.h @@ -79,7 +79,7 @@ public: std::function columnSwitch; }; - explicit HexDump(QWidget* parent = 0); + explicit HexDump(QWidget* parent = 0, MemoryPage* memPage = 0); ~HexDump() override; // Configuration diff --git a/src/gui/Src/Memory/MemoryPage.h b/src/gui/Src/Memory/MemoryPage.h index 01213b74..e6a5bb50 100644 --- a/src/gui/Src/Memory/MemoryPage.h +++ b/src/gui/Src/Memory/MemoryPage.h @@ -9,15 +9,15 @@ class MemoryPage : public QObject public: explicit MemoryPage(duint parBase, duint parSize, QObject* parent = 0); - bool read(void* parDest, dsint parRVA, duint parSize) const; - bool write(const void* parDest, dsint parRVA, duint parSize); + virtual bool read(void* parDest, dsint parRVA, duint parSize) const; + virtual bool write(const void* parDest, dsint parRVA, duint parSize); duint getSize() const; duint getBase() const; duint va(dsint rva) const; void setAttributes(duint base, duint size); bool inRange(duint va) const; -private: +protected: duint mBase; duint mSize; }; diff --git a/src/gui/Src/Tracer/TraceDump.cpp b/src/gui/Src/Tracer/TraceDump.cpp new file mode 100644 index 00000000..f4da1087 --- /dev/null +++ b/src/gui/Src/Tracer/TraceDump.cpp @@ -0,0 +1,1575 @@ +#include "TraceDump.h" +#include "TraceFileReader.h" +#include "TraceFileDump.h" +#include +#include +#include +#include +#include "Configuration.h" +#include "Bridge.h" +#include "HexEditDialog.h" +//#include "CPUMultiDump.h" +#include "GotoDialog.h" +#include "TraceBrowser.h" +#include "CommonActions.h" +#include "WordEditDialog.h" +#include "CodepageSelectionDialog.h" +#include "MiscUtil.h" +#include "BackgroundFlickerThread.h" + +TraceDump::TraceDump(TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent) : mMemoryPage(memoryPage), HexDump(parent, memoryPage) +{ + mDisas = disas; + //mMultiDump = multiDump; + + duint setting; + if(BridgeSettingGetUint("Gui", "AsciiSeparator", &setting)) + mAsciiSeparator = setting & 0xF; + + setView((ViewEnum_t)ConfigUint("HexDump", "DefaultView")); + + connect(this, SIGNAL(selectionUpdated()), this, SLOT(selectionUpdatedSlot())); + connect(this, SIGNAL(headerButtonReleased(int)), this, SLOT(headerButtonReleasedSlot(int))); + + //mPluginMenu = multiDump->mDumpPluginMenu; + + setupContextMenu(); +} + +void TraceDump::setupContextMenu() +{ + mMenuBuilder = new MenuBuilder(this, [](QMenu*) + { + return DbgIsDebugging(); + }); + + mCommonActions = new CommonActions(this, getActionHelperFuncs(), [this]() + { + return rvaToVa(getSelectionStart()); + }); + + MenuBuilder* wBinaryMenu = new MenuBuilder(this); + //wBinaryMenu->addAction(makeShortcutAction(DIcon("binary_edit"), tr("&Edit"), SLOT(binaryEditSlot()), "ActionBinaryEdit")); + //wBinaryMenu->addAction(makeShortcutAction(DIcon("binary_fill"), tr("&Fill..."), SLOT(binaryFillSlot()), "ActionBinaryFill")); + //wBinaryMenu->addSeparator(); + wBinaryMenu->addAction(makeShortcutAction(DIcon("binary_copy"), tr("&Copy"), SLOT(binaryCopySlot()), "ActionBinaryCopy")); + //wBinaryMenu->addAction(makeShortcutAction(DIcon("binary_paste"), tr("&Paste"), SLOT(binaryPasteSlot()), "ActionBinaryPaste"), [](QMenu*) + //{ + // return QApplication::clipboard()->mimeData()->hasText(); + //}); + //wBinaryMenu->addAction(makeShortcutAction(DIcon("binary_paste_ignoresize"), tr("Paste (&Ignore Size)"), SLOT(binaryPasteIgnoreSizeSlot()), "ActionBinaryPasteIgnoreSize"), [](QMenu*) + //{ + // return QApplication::clipboard()->mimeData()->hasText(); + //}); + wBinaryMenu->addAction(makeShortcutAction(DIcon("binary_save"), tr("Save To a File"), SLOT(binarySaveToFileSlot()), "ActionBinarySave")); + mMenuBuilder->addMenu(makeMenu(DIcon("binary"), tr("B&inary")), wBinaryMenu); + + MenuBuilder* wCopyMenu = new MenuBuilder(this); + wCopyMenu->addAction(mCopySelection); + wCopyMenu->addAction(mCopyAddress); + wCopyMenu->addAction(mCopyRva, [this](QMenu*) + { + return DbgFunctions()->ModBaseFromAddr(rvaToVa(getInitialSelection())) != 0; + }); + wCopyMenu->addAction(makeShortcutAction(DIcon("fileoffset"), tr("&File Offset"), SLOT(copyFileOffsetSlot()), "ActionCopyFileOffset"), [this](QMenu*) + { + return DbgFunctions()->VaToFileOffset(rvaToVa(getInitialSelection())) != 0; + }); + + mMenuBuilder->addMenu(makeMenu(DIcon("copy"), tr("&Copy")), wCopyMenu); + + mMenuBuilder->addAction(makeShortcutAction(DIcon("eraser"), tr("&Restore selection"), SLOT(undoSelectionSlot()), "ActionUndoSelection"), [this](QMenu*) + { + return DbgFunctions()->PatchInRange(rvaToVa(getSelectionStart()), rvaToVa(getSelectionEnd())); + }); + + mCommonActions->build(mMenuBuilder, CommonActions::ActionDisasm | CommonActions::ActionMemoryMap | CommonActions::ActionDumpData | CommonActions::ActionDumpN + | CommonActions::ActionDisasmData | CommonActions::ActionStackDump | CommonActions::ActionLabel | CommonActions::ActionWatch); + auto wIsValidReadPtrCallback = [this](QMenu*) + { + duint ptr = 0; + DbgMemRead(rvaToVa(getSelectionStart()), (unsigned char*)&ptr, sizeof(duint)); + return DbgMemIsValidReadPtr(ptr); + }; + + mMenuBuilder->addAction(makeShortcutAction(DIcon("modify"), tr("&Modify Value"), SLOT(modifyValueSlot()), "ActionModifyValue"), [this](QMenu*) + { + auto d = mDescriptor.at(0).data; + return getSizeOf(d.itemSize) <= sizeof(duint) || (d.itemSize == 4 && d.dwordMode == FloatDword || d.itemSize == 8 && d.qwordMode == DoubleQword); + }); + + MenuBuilder* wBreakpointMenu = new MenuBuilder(this); + MenuBuilder* wHardwareAccessMenu = new MenuBuilder(this, [this](QMenu*) + { + return (DbgGetBpxTypeAt(rvaToVa(getSelectionStart())) & bp_hardware) == 0; + }); + MenuBuilder* wHardwareWriteMenu = new MenuBuilder(this, [this](QMenu*) + { + return (DbgGetBpxTypeAt(rvaToVa(getSelectionStart())) & bp_hardware) == 0; + }); + MenuBuilder* wMemoryAccessMenu = new MenuBuilder(this, [this](QMenu*) + { + return (DbgGetBpxTypeAt(rvaToVa(getSelectionStart())) & bp_memory) == 0; + }); + MenuBuilder* wMemoryReadMenu = new MenuBuilder(this, [this](QMenu*) + { + return (DbgGetBpxTypeAt(rvaToVa(getSelectionStart())) & bp_memory) == 0; + }); + MenuBuilder* wMemoryWriteMenu = new MenuBuilder(this, [this](QMenu*) + { + return (DbgGetBpxTypeAt(rvaToVa(getSelectionStart())) & bp_memory) == 0; + }); + MenuBuilder* wMemoryExecuteMenu = new MenuBuilder(this, [this](QMenu*) + { + return (DbgGetBpxTypeAt(rvaToVa(getSelectionStart())) & bp_memory) == 0; + }); + wHardwareAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_byte"), tr("&Byte"), "bphws $, r, 1")); + wHardwareAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_word"), tr("&Word"), "bphws $, r, 2")); + wHardwareAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_dword"), tr("&Dword"), "bphws $, r, 4")); +#ifdef _WIN64 + wHardwareAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_qword"), tr("&Qword"), "bphws $, r, 8")); +#endif //_WIN64 + wHardwareWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_byte"), tr("&Byte"), "bphws $, w, 1")); + wHardwareWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_word"), tr("&Word"), "bphws $, w, 2")); + wHardwareWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_dword"), tr("&Dword"), "bphws $, w, 4")); +#ifdef _WIN64 + wHardwareWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_qword"), tr("&Qword"), "bphws $, w, 8")); +#endif //_WIN64 + wBreakpointMenu->addMenu(makeMenu(DIcon("breakpoint_access"), tr("Hardware, &Access")), wHardwareAccessMenu); + wBreakpointMenu->addMenu(makeMenu(DIcon("breakpoint_write"), tr("Hardware, &Write")), wHardwareWriteMenu); + wBreakpointMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_execute"), tr("Hardware, &Execute"), "bphws $, x"), [this](QMenu*) + { + return (DbgGetBpxTypeAt(rvaToVa(getSelectionStart())) & bp_hardware) == 0; + }); + wBreakpointMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_remove"), tr("Remove &Hardware"), "bphwc $"), [this](QMenu*) + { + return (DbgGetBpxTypeAt(rvaToVa(getSelectionStart())) & bp_hardware) != 0; + }); + wBreakpointMenu->addSeparator(); + wMemoryAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_memory_singleshoot"), tr("&Singleshoot"), "bpm $, 0, a")); + wMemoryAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_memory_restore_on_hit"), tr("&Restore on hit"), "bpm $, 1, a")); + wMemoryReadMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_memory_singleshoot"), tr("&Singleshoot"), "bpm $, 0, r")); + wMemoryReadMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_memory_restore_on_hit"), tr("&Restore on hit"), "bpm $, 1, r")); + wMemoryWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_memory_singleshoot"), tr("&Singleshoot"), "bpm $, 0, w")); + wMemoryWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_memory_restore_on_hit"), tr("&Restore on hit"), "bpm $, 1, w")); + wMemoryExecuteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_memory_singleshoot"), tr("&Singleshoot"), "bpm $, 0, x")); + wMemoryExecuteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_memory_restore_on_hit"), tr("&Restore on hit"), "bpm $, 1, x")); + wBreakpointMenu->addMenu(makeMenu(DIcon("breakpoint_memory_access"), tr("Memory, Access")), wMemoryAccessMenu); + wBreakpointMenu->addMenu(makeMenu(DIcon("breakpoint_memory_read"), tr("Memory, Read")), wMemoryReadMenu); + wBreakpointMenu->addMenu(makeMenu(DIcon("breakpoint_memory_write"), tr("Memory, Write")), wMemoryWriteMenu); + wBreakpointMenu->addMenu(makeMenu(DIcon("breakpoint_memory_execute"), tr("Memory, Execute")), wMemoryExecuteMenu); + wBreakpointMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_remove"), tr("Remove &Memory"), "bpmc $"), [this](QMenu*) + { + return (DbgGetBpxTypeAt(rvaToVa(getSelectionStart())) & bp_memory) != 0; + }); + mMenuBuilder->addMenu(makeMenu(DIcon("breakpoint"), tr("&Breakpoint")), wBreakpointMenu); + + mMenuBuilder->addAction(makeShortcutAction(DIcon("search-for"), tr("&Find Pattern..."), SLOT(findPattern()), "ActionFindPattern")); + mMenuBuilder->addAction(makeShortcutAction(DIcon("find"), tr("Find &References"), SLOT(findReferencesSlot()), "ActionFindReferences")); + + mMenuBuilder->addAction(makeShortcutAction(DIcon("sync"), tr("&Sync with expression"), SLOT(syncWithExpressionSlot()), "ActionSync")); + mMenuBuilder->addAction(makeShortcutAction(DIcon("memmap_alloc_memory"), tr("Allocate Memory"), SLOT(allocMemorySlot()), "ActionAllocateMemory")); + + MenuBuilder* wGotoMenu = new MenuBuilder(this); + wGotoMenu->addAction(makeShortcutAction(DIcon("geolocation-goto"), tr("&Expression"), SLOT(gotoExpressionSlot()), "ActionGotoExpression")); + wGotoMenu->addAction(makeShortcutAction(DIcon("fileoffset"), tr("File Offset"), SLOT(gotoFileOffsetSlot()), "ActionGotoFileOffset")); + wGotoMenu->addAction(makeShortcutAction(DIcon("top"), tr("Start of Page"), SLOT(gotoStartSlot()), "ActionGotoStart"), [this](QMenu*) + { + return getSelectionStart() != 0; + }); + wGotoMenu->addAction(makeShortcutAction(DIcon("bottom"), tr("End of Page"), SLOT(gotoEndSlot()), "ActionGotoEnd")); + wGotoMenu->addAction(makeShortcutAction(DIcon("previous"), tr("Previous"), SLOT(gotoPreviousSlot()), "ActionGotoPrevious"), [this](QMenu*) + { + return mHistory.historyHasPrev(); + }); + wGotoMenu->addAction(makeShortcutAction(DIcon("next"), tr("Next"), SLOT(gotoNextSlot()), "ActionGotoNext"), [this](QMenu*) + { + return mHistory.historyHasNext(); + }); + wGotoMenu->addAction(makeShortcutAction(DIcon("prevref"), tr("Previous Reference"), SLOT(gotoPreviousReferenceSlot()), "ActionGotoPreviousReference"), [](QMenu*) + { + return !!DbgEval("refsearch.count() && ($__dump_refindex > 0 || dump.sel() != refsearch.addr($__dump_refindex))"); + }); + wGotoMenu->addAction(makeShortcutAction(DIcon("nextref"), tr("Next Reference"), SLOT(gotoNextReferenceSlot()), "ActionGotoNextReference"), [](QMenu*) + { + return !!DbgEval("refsearch.count() && ($__dump_refindex < refsearch.count() || dump.sel() != refsearch.addr($__dump_refindex))"); + }); + mMenuBuilder->addMenu(makeMenu(DIcon("goto"), tr("&Go to")), wGotoMenu); + mMenuBuilder->addSeparator(); + + MenuBuilder* wHexMenu = new MenuBuilder(this); + wHexMenu->addAction(makeAction(DIcon("ascii"), tr("&ASCII"), SLOT(hexAsciiSlot()))); + wHexMenu->addAction(makeAction(DIcon("ascii-extended"), tr("&Extended ASCII"), SLOT(hexUnicodeSlot()))); + QAction* wHexLastCodepage = makeAction(DIcon("codepage"), "?", SLOT(hexLastCodepageSlot())); + wHexMenu->addAction(wHexLastCodepage, [wHexLastCodepage](QMenu*) + { + duint lastCodepage; + auto allCodecs = QTextCodec::availableCodecs(); + if(!BridgeSettingGetUint("Misc", "LastCodepage", &lastCodepage) || lastCodepage >= duint(allCodecs.size())) + return false; + wHexLastCodepage->setText(QString::fromLocal8Bit(allCodecs.at(lastCodepage))); + return true; + }); + wHexMenu->addAction(makeAction(DIcon("codepage"), tr("&Codepage..."), SLOT(hexCodepageSlot()))); + mMenuBuilder->addMenu(makeMenu(DIcon("hex"), tr("&Hex")), wHexMenu); + + MenuBuilder* wTextMenu = new MenuBuilder(this); + wTextMenu->addAction(makeAction(DIcon("ascii"), tr("&ASCII"), SLOT(textAsciiSlot()))); + wTextMenu->addAction(makeAction(DIcon("ascii-extended"), tr("&Extended ASCII"), SLOT(textUnicodeSlot()))); + QAction* wTextLastCodepage = makeAction(DIcon("codepage"), "?", SLOT(textLastCodepageSlot())); + wTextMenu->addAction(wTextLastCodepage, [wTextLastCodepage](QMenu*) + { + duint lastCodepage; + auto allCodecs = QTextCodec::availableCodecs(); + if(!BridgeSettingGetUint("Misc", "LastCodepage", &lastCodepage) || lastCodepage >= duint(allCodecs.size())) + return false; + wTextLastCodepage->setText(QString::fromLocal8Bit(allCodecs.at(lastCodepage))); + return true; + }); + wTextMenu->addAction(makeAction(DIcon("codepage"), tr("&Codepage..."), SLOT(textCodepageSlot()))); + mMenuBuilder->addMenu(makeMenu(DIcon("strings"), tr("&Text")), wTextMenu); + + MenuBuilder* wIntegerMenu = new MenuBuilder(this); + wIntegerMenu->addAction(makeAction(DIcon("byte"), tr("Signed byte (8-bit)"), SLOT(integerSignedByteSlot()))); + wIntegerMenu->addAction(makeAction(DIcon("word"), tr("Signed short (16-bit)"), SLOT(integerSignedShortSlot()))); + wIntegerMenu->addAction(makeAction(DIcon("dword"), tr("Signed long (32-bit)"), SLOT(integerSignedLongSlot()))); + wIntegerMenu->addAction(makeAction(DIcon("qword"), tr("Signed long long (64-bit)"), SLOT(integerSignedLongLongSlot()))); + wIntegerMenu->addAction(makeAction(DIcon("byte"), tr("Unsigned byte (8-bit)"), SLOT(integerUnsignedByteSlot()))); + wIntegerMenu->addAction(makeAction(DIcon("word"), tr("Unsigned short (16-bit)"), SLOT(integerUnsignedShortSlot()))); + wIntegerMenu->addAction(makeAction(DIcon("dword"), tr("Unsigned long (32-bit)"), SLOT(integerUnsignedLongSlot()))); + wIntegerMenu->addAction(makeAction(DIcon("qword"), tr("Unsigned long long (64-bit)"), SLOT(integerUnsignedLongLongSlot()))); + wIntegerMenu->addAction(makeAction(DIcon("word"), tr("Hex short (16-bit)"), SLOT(integerHexShortSlot()))); + wIntegerMenu->addAction(makeAction(DIcon("dword"), tr("Hex long (32-bit)"), SLOT(integerHexLongSlot()))); + wIntegerMenu->addAction(makeAction(DIcon("qword"), tr("Hex long long (64-bit)"), SLOT(integerHexLongLongSlot()))); + mMenuBuilder->addMenu(makeMenu(DIcon("integer"), tr("&Integer")), wIntegerMenu); + + MenuBuilder* wFloatMenu = new MenuBuilder(this); + wFloatMenu->addAction(makeAction(DIcon("32bit-float"), tr("&Float (32-bit)"), SLOT(floatFloatSlot()))); + wFloatMenu->addAction(makeAction(DIcon("64bit-float"), tr("&Double (64-bit)"), SLOT(floatDoubleSlot()))); + wFloatMenu->addAction(makeAction(DIcon("80bit-float"), tr("&Long double (80-bit)"), SLOT(floatLongDoubleSlot()))); + mMenuBuilder->addMenu(makeMenu(DIcon("float"), tr("&Float")), wFloatMenu); + + mMenuBuilder->addAction(makeAction(DIcon("address"), tr("&Address"), SLOT(addressAsciiSlot()))); + mMenuBuilder->addAction(makeAction(DIcon("processor-cpu"), tr("&Disassembly"), SLOT(disassemblySlot()))); + + //mMenuBuilder->addSeparator(); + //mMenuBuilder->addBuilder(new MenuBuilder(this, [this](QMenu * menu) + //{ + // DbgMenuPrepare(GUI_DUMP_MENU); + // menu->addActions(mPluginMenu->actions()); + // return true; + //})); + + mMenuBuilder->loadFromConfig(); + updateShortcuts(); +} + +void TraceDump::getAttention() +{ + BackgroundFlickerThread* thread = new BackgroundFlickerThread(this, mBackgroundColor, this); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + thread->start(); +} + +void TraceDump::getColumnRichText(int col, dsint rva, RichTextPainter::List & richText) +{ + if(col && !mDescriptor.at(col - 1).isData && mDescriptor.at(col - 1).itemCount) //print comments + { + RichTextPainter::CustomRichText_t curData; + curData.flags = RichTextPainter::FlagColor; + curData.textColor = mTextColor; + duint data = 0; + mMemPage->read((byte_t*)&data, rva, sizeof(duint)); + + char modname[MAX_MODULE_SIZE] = ""; + if(!DbgGetModuleAt(data, modname)) + modname[0] = '\0'; + char label_text[MAX_LABEL_SIZE] = ""; + char string_text[MAX_STRING_SIZE] = ""; + if(DbgGetLabelAt(data, SEG_DEFAULT, label_text)) + curData.text = QString(modname) + "." + QString(label_text); + else if(DbgGetStringAt(data, string_text)) + curData.text = string_text; + if(!curData.text.length()) //stack comments + { + auto va = rvaToVa(rva); + duint stackSize; + duint csp = DbgValFromString("csp"); + duint stackBase = DbgMemFindBaseAddr(csp, &stackSize); + STACK_COMMENT comment; + if(va >= stackBase && va < stackBase + stackSize && DbgStackCommentGet(va, &comment)) + { + if(va >= csp) //active stack + { + if(*comment.color) + curData.textColor = QColor(QString(comment.color)); + } + else + curData.textColor = ConfigColor("StackInactiveTextColor"); + curData.text = comment.comment; + } + } + if(curData.text.length()) + richText.push_back(curData); + } + else + HexDump::getColumnRichText(col, rva, richText); +} + +QString TraceDump::paintContent(QPainter* painter, dsint rowBase, int rowOffset, int col, int x, int y, int w, int h) +{ + // Reset byte offset when base address is reached + if(rowBase == 0 && mByteOffset != 0) + printDumpAt(mMemPage->getBase(), false, false); + + if(!col) //address + { + char label[MAX_LABEL_SIZE] = ""; + dsint cur_addr = rvaToVa((rowBase + rowOffset) * getBytePerRowCount() - mByteOffset); + QColor background; + if(DbgGetLabelAt(cur_addr, SEG_DEFAULT, label)) //label + { + background = ConfigColor("HexDumpLabelBackgroundColor"); + painter->setPen(ConfigColor("HexDumpLabelColor")); //TODO: config + } + else + { + background = ConfigColor("HexDumpAddressBackgroundColor"); + painter->setPen(ConfigColor("HexDumpAddressColor")); //TODO: config + } + if(background.alpha()) + painter->fillRect(QRect(x, y, w, h), QBrush(background)); //fill background color + painter->drawText(QRect(x + 4, y, w - 4, h), Qt::AlignVCenter | Qt::AlignLeft, makeAddrText(cur_addr)); + return QString(); + } + return HexDump::paintContent(painter, rowBase, rowOffset, col, x, y, w, h); +} + +void TraceDump::contextMenuEvent(QContextMenuEvent* event) +{ + QMenu wMenu(this); + mMenuBuilder->build(&wMenu); + wMenu.exec(event->globalPos()); +} + +void TraceDump::mouseDoubleClickEvent(QMouseEvent* event) +{ + if(event->button() != Qt::LeftButton || !DbgIsDebugging()) + return; + switch(getColumnIndexFromX(event->x())) + { + case 0: //address + { + //very ugly way to calculate the base of the current row (no clue why it works) + dsint deltaRowBase = getInitialSelection() % getBytePerRowCount() + mByteOffset; + if(deltaRowBase >= getBytePerRowCount()) + deltaRowBase -= getBytePerRowCount(); + dsint mSelectedVa = rvaToVa(getInitialSelection() - deltaRowBase); + if(mRvaDisplayEnabled && mSelectedVa == mRvaDisplayBase) + mRvaDisplayEnabled = false; + else + { + mRvaDisplayEnabled = true; + mRvaDisplayBase = mSelectedVa; + mRvaDisplayPageBase = mMemPage->getBase(); + } + reloadData(); + } + break; + + default: + { + auto d = mDescriptor.at(0).data; + if(getSizeOf(d.itemSize) <= sizeof(duint) || (d.itemSize == 4 && d.dwordMode == FloatDword || d.itemSize == 8 && d.qwordMode == DoubleQword)) + modifyValueSlot(); + else + binaryEditSlot(); + } + break; + } +} + +#ifdef TODO +static QString getTooltipForVa(duint va, int depth) +{ + duint ptr = 0; + if(!HexDump::mMemPage->read(va, &ptr, sizeof(duint))) + return QString(); + + QString tooltip; + /* TODO: if this is enabled, make sure the context menu items also work + // If the VA is not a valid pointer, try to align it + if(!DbgMemIsValidReadPtr(ptr)) + { + va -= va % sizeof(duint); + DbgMemRead(va, &ptr, sizeof(duint)); + }*/ + + // Check if its a pointer + switch(DbgGetEncodeTypeAt(va, 1)) + { + // Get information about the pointer type + case enc_unknown: + default: + if(DbgMemIsValidReadPtr(ptr) && depth >= 0) + { + tooltip = QString("[%1] = %2").arg(ToPtrString(ptr), getTooltipForVa(ptr, depth - 1)); + } + // If not a pointer, hide tooltips + else + { + bool isCodePage; + isCodePage = DbgFunctions()->MemIsCodePage(va, false); + char disassembly[GUI_MAX_DISASSEMBLY_SIZE]; + if(isCodePage) + { + if(GuiGetDisassembly(va, disassembly)) + tooltip = QString::fromUtf8(disassembly); + else + tooltip = ""; + } + else + tooltip = QString("[%1] = %2").arg(ToPtrString(va)).arg(ToPtrString(ptr)); + if(DbgFunctions()->ModGetParty(va) == 1) + tooltip += " (" + (isCodePage ? TraceDump::tr("System Code") : TraceDump::tr("System Data")) + ")"; + else + tooltip += " (" + (isCodePage ? TraceDump::tr("User Code") : TraceDump::tr("User Data")) + ")"; + } + break; + case enc_code: + char disassembly[GUI_MAX_DISASSEMBLY_SIZE]; + if(GuiGetDisassembly(va, disassembly)) + tooltip = QString::fromUtf8(disassembly); + else + tooltip = ""; + if(DbgFunctions()->ModGetParty(va) == 1) + tooltip += " (" + TraceDump::tr("System Code") + ")"; + else + tooltip += " (" + TraceDump::tr("User Code") + ")"; + break; + case enc_real4: + tooltip = ToFloatString(&va) + TraceDump::tr(" (Real4)"); + break; + case enc_real8: + double numd; + DbgMemRead(va, &numd, sizeof(double)); + tooltip = ToDoubleString(&numd) + TraceDump::tr(" (Real8)"); + break; + case enc_byte: + tooltip = ToByteString(va) + TraceDump::tr(" (BYTE)"); + break; + case enc_word: + tooltip = ToWordString(va) + TraceDump::tr(" (WORD)"); + break; + case enc_dword: + tooltip = QString("%1").arg((unsigned int)va, 8, 16, QChar('0')).toUpper() + TraceDump::tr(" (DWORD)"); + break; + case enc_qword: +#ifdef _WIN64 + tooltip = QString("%1").arg((unsigned long long)va, 16, 16, QChar('0')).toUpper() + TraceDump::tr(" (QWORD)"); +#else //x86 + unsigned long long qword; + qword = 0; + DbgMemRead(va, &qword, 8); + tooltip = QString("%1").arg((unsigned long long)qword, 16, 16, QChar('0')).toUpper() + TraceDump::tr(" (QWORD)"); +#endif //_WIN64 + break; + case enc_ascii: + case enc_unicode: + char str[MAX_STRING_SIZE]; + if(DbgGetStringAt(va, str)) + tooltip = QString::fromUtf8(str) + TraceDump::tr(" (String)"); + else + tooltip = TraceDump::tr("(Unknown String)"); + break; + } + return tooltip; +} +#else +static QString getTooltipForVa(duint va, int depth) +{ + return QString(); +} +#endif + +void TraceDump::mouseMoveEvent(QMouseEvent* event) +{ + // Get mouse pointer relative position + int x = event->x(); + int y = event->y(); + + // Get HexDump own RVA address, then VA in memory + auto va = rvaToVa(getItemStartingAddress(x, y)); + + // Read VA + QToolTip::showText(event->globalPos(), getTooltipForVa(va, 4)); + + HexDump::mouseMoveEvent(event); +} + +void TraceDump::modifyValueSlot() +{ + dsint addr = getSelectionStart(); + auto d = mDescriptor.at(0).data; + if(d.itemSize == 4 && d.dwordMode == FloatDword || d.itemSize == 8 && d.qwordMode == DoubleQword) + { + auto size = std::min(getSizeOf(mDescriptor.at(0).data.itemSize), sizeof(double)); + if(size == 4) + { + float value; + mMemPage->read(&value, addr, size); + QString current = QString::number(value); + QString newvalue; + if(SimpleInputBox(this, tr("Modify value"), current, newvalue, current)) + { + bool ok; + value = newvalue.toFloat(&ok); + if(ok) + mMemPage->write(&value, addr, size); + else + SimpleErrorBox(this, tr("Error"), tr("The input text is not a number!")); + } + } + else if(size == 8) + { + double value; + mMemPage->read(&value, addr, size); + QString current = QString::number(value); + QString newvalue; + if(SimpleInputBox(this, tr("Modify value"), current, newvalue, current)) + { + bool ok; + value = newvalue.toDouble(&ok); + if(ok) + mMemPage->write(&value, addr, size); + else + SimpleErrorBox(this, tr("Error"), tr("The input text is not a number!")); + } + } + } + else + { + auto size = std::min(getSizeOf(mDescriptor.at(0).data.itemSize), sizeof(dsint)); + WordEditDialog wEditDialog(this); + dsint value = 0; + mMemPage->read(&value, addr, size); + wEditDialog.setup(tr("Modify value"), value, (int)size); + if(wEditDialog.exec() != QDialog::Accepted) + return; + value = wEditDialog.getVal(); + mMemPage->write(&value, addr, size); + } + GuiUpdateAllViews(); +} + +void TraceDump::gotoExpressionSlot() +{ + if(!DbgIsDebugging()) + return; + if(!mGoto) + mGoto = new GotoDialog(this); + mGoto->setWindowTitle(tr("Enter expression to follow in Dump...")); + mGoto->setInitialExpression(ToPtrString(rvaToVa(getInitialSelection()))); + if(mGoto->exec() == QDialog::Accepted) + { + duint value = DbgValFromString(mGoto->expressionText.toUtf8().constData()); + DbgCmdExec(QString().sprintf("dump %p", value)); + } +} + +void TraceDump::gotoFileOffsetSlot() +{ + if(!DbgIsDebugging()) + return; + char modname[MAX_MODULE_SIZE] = ""; + if(!DbgFunctions()->ModNameFromAddr(rvaToVa(getSelectionStart()), modname, true)) + { + SimpleErrorBox(this, tr("Error!"), tr("Not inside a module...")); + return; + } + if(!mGotoOffset) + mGotoOffset = new GotoDialog(this); + mGotoOffset->fileOffset = true; + mGotoOffset->modName = QString(modname); + mGotoOffset->setWindowTitle(tr("Goto File Offset in %1").arg(QString(modname))); + duint addr = rvaToVa(getInitialSelection()); + duint offset = DbgFunctions()->VaToFileOffset(addr); + if(offset) + mGotoOffset->setInitialExpression(ToHexString(offset)); + if(mGotoOffset->exec() != QDialog::Accepted) + return; + duint value = DbgValFromString(mGotoOffset->expressionText.toUtf8().constData()); + value = DbgFunctions()->FileOffsetToVa(modname, value); + DbgCmdExec(QString().sprintf("dump \"%p\"", value)); +} + +void TraceDump::gotoStartSlot() +{ + duint dest = mMemPage->getBase(); + DbgCmdExec(QString().sprintf("dump \"%p\"", dest)); +} + +void TraceDump::gotoEndSlot() +{ + duint dest = mMemPage->getBase() + mMemPage->getSize() - (getViewableRowsCount() * getBytePerRowCount()); + DbgCmdExec(QString().sprintf("dump \"%p\"", dest)); +} + +void TraceDump::gotoPreviousReferenceSlot() +{ + auto count = DbgEval("refsearch.count()"), index = DbgEval("$__dump_refindex"), addr = DbgEval("refsearch.addr($__dump_refindex)"); + if(count) + { + if(index > 0 && addr == rvaToVa(getInitialSelection())) + DbgValToString("$__dump_refindex", index - 1); + DbgCmdExec("dump refsearch.addr($__dump_refindex)"); + } +} + +void TraceDump::gotoNextReferenceSlot() +{ + auto count = DbgEval("refsearch.count()"), index = DbgEval("$__dump_refindex"), addr = DbgEval("refsearch.addr($__dump_refindex)"); + if(count) + { + if(index + 1 < count && addr == rvaToVa(getInitialSelection())) + DbgValToString("$__dump_refindex", index + 1); + DbgCmdExec("dump refsearch.addr($__dump_refindex)"); + } +} + +void TraceDump::hexAsciiSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewHexAscii); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //hex byte + wColDesc.itemCount = 16; + wColDesc.separator = mAsciiSeparator ? mAsciiSeparator : 4; + dDesc.itemSize = Byte; + dDesc.byteMode = HexByte; + wColDesc.data = dDesc; + appendResetDescriptor(8 + charwidth * 47, tr("Hex"), false, wColDesc); + + wColDesc.isData = true; //ascii byte + wColDesc.itemCount = 16; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(8 + charwidth * 16, tr("ASCII"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::hexUnicodeSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewHexUnicode); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //hex byte + wColDesc.itemCount = 16; + wColDesc.separator = mAsciiSeparator ? mAsciiSeparator : 4; + dDesc.itemSize = Byte; + dDesc.byteMode = HexByte; + wColDesc.data = dDesc; + appendResetDescriptor(8 + charwidth * 47, tr("Hex"), false, wColDesc); + + wColDesc.isData = true; //unicode short + wColDesc.itemCount = 8; + wColDesc.separator = 0; + dDesc.itemSize = Word; + dDesc.wordMode = UnicodeWord; + wColDesc.data = dDesc; + appendDescriptor(8 + charwidth * 8, tr("UNICODE"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::hexCodepageSlot() +{ + CodepageSelectionDialog dialog(this); + if(dialog.exec() != QDialog::Accepted) + return; + auto codepage = dialog.getSelectedCodepage(); + + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //hex byte + wColDesc.itemCount = 16; + wColDesc.separator = mAsciiSeparator ? mAsciiSeparator : 4; + dDesc.itemSize = Byte; + dDesc.byteMode = HexByte; + wColDesc.data = dDesc; + appendResetDescriptor(8 + charwidth * 47, tr("Hex"), false, wColDesc); + + wColDesc.isData = true; //text (in code page) + wColDesc.itemCount = 16; + wColDesc.separator = 0; + wColDesc.textCodec = QTextCodec::codecForName(codepage); + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, codepage, false, wColDesc); + + reloadData(); +} + +void TraceDump::hexLastCodepageSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewHexCodepage); + + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + duint lastCodepage; + auto allCodecs = QTextCodec::availableCodecs(); + if(!BridgeSettingGetUint("Misc", "LastCodepage", &lastCodepage) || lastCodepage >= duint(allCodecs.size())) + return; + + wColDesc.isData = true; //hex byte + wColDesc.itemCount = 16; + wColDesc.separator = mAsciiSeparator ? mAsciiSeparator : 4; + dDesc.itemSize = Byte; + dDesc.byteMode = HexByte; + wColDesc.data = dDesc; + appendResetDescriptor(8 + charwidth * 47, tr("Hex"), false, wColDesc); + + wColDesc.isData = true; //text (in code page) + wColDesc.itemCount = 16; + wColDesc.separator = 0; + wColDesc.textCodec = QTextCodec::codecForName(allCodecs.at(lastCodepage)); + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, allCodecs.at(lastCodepage), false, wColDesc); + + reloadData(); +} + +void TraceDump::textLastCodepageSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewTextCodepage); + + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + duint lastCodepage; + auto allCodecs = QTextCodec::availableCodecs(); + if(!BridgeSettingGetUint("Misc", "LastCodepage", &lastCodepage) || lastCodepage >= duint(allCodecs.size())) + return; + + wColDesc.isData = true; //text (in code page) + wColDesc.itemCount = 64; + wColDesc.separator = 0; + wColDesc.textCodec = QTextCodec::codecForName(allCodecs.at(lastCodepage)); + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendResetDescriptor(0, allCodecs.at(lastCodepage), false, wColDesc); + + reloadData(); +} + +void TraceDump::textAsciiSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewTextAscii); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //ascii byte + wColDesc.itemCount = 64; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendResetDescriptor(8 + charwidth * 64, tr("ASCII"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::textUnicodeSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewTextUnicode); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //unicode short + wColDesc.itemCount = 64; + wColDesc.separator = 0; + dDesc.itemSize = Word; + dDesc.wordMode = UnicodeWord; + wColDesc.data = dDesc; + appendResetDescriptor(8 + charwidth * 64, tr("UNICODE"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::textCodepageSlot() +{ + CodepageSelectionDialog dialog(this); + if(dialog.exec() != QDialog::Accepted) + return; + auto codepage = dialog.getSelectedCodepage(); + + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //text (in code page) + wColDesc.itemCount = 64; + wColDesc.separator = 0; + wColDesc.textCodec = QTextCodec::codecForName(codepage); + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendResetDescriptor(0, codepage, false, wColDesc); + + reloadData(); +} + +void TraceDump::integerSignedByteSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewIntegerSignedByte); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //signed short + wColDesc.itemCount = 8; + wColDesc.separator = 0; + wColDesc.data.itemSize = Byte; + wColDesc.data.wordMode = SignedDecWord; + appendResetDescriptor(8 + charwidth * 40, tr("Signed byte (8-bit)"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::integerSignedShortSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewIntegerSignedShort); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //signed short + wColDesc.itemCount = 8; + wColDesc.separator = 0; + wColDesc.data.itemSize = Word; + wColDesc.data.wordMode = SignedDecWord; + appendResetDescriptor(8 + charwidth * 55, tr("Signed short (16-bit)"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::integerSignedLongSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewIntegerSignedLong); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //signed long + wColDesc.itemCount = 4; + wColDesc.separator = 0; + wColDesc.data.itemSize = Dword; + wColDesc.data.dwordMode = SignedDecDword; + appendResetDescriptor(8 + charwidth * 47, tr("Signed long (32-bit)"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::integerSignedLongLongSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewIntegerSignedLongLong); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //signed long long + wColDesc.itemCount = 2; + wColDesc.separator = 0; + wColDesc.data.itemSize = Qword; + wColDesc.data.qwordMode = SignedDecQword; + appendResetDescriptor(8 + charwidth * 41, tr("Signed long long (64-bit)"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::integerUnsignedByteSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewIntegerUnsignedByte); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //unsigned short + wColDesc.itemCount = 8; + wColDesc.separator = 0; + wColDesc.data.itemSize = Byte; + wColDesc.data.wordMode = UnsignedDecWord; + appendResetDescriptor(8 + charwidth * 32, tr("Unsigned byte (8-bit)"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::integerUnsignedShortSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewIntegerUnsignedShort); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //unsigned short + wColDesc.itemCount = 8; + wColDesc.separator = 0; + wColDesc.data.itemSize = Word; + wColDesc.data.wordMode = UnsignedDecWord; + appendResetDescriptor(8 + charwidth * 47, tr("Unsigned short (16-bit)"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::integerUnsignedLongSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewIntegerUnsignedLong); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //unsigned long + wColDesc.itemCount = 4; + wColDesc.separator = 0; + wColDesc.data.itemSize = Dword; + wColDesc.data.dwordMode = UnsignedDecDword; + appendResetDescriptor(8 + charwidth * 43, tr("Unsigned long (32-bit)"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::integerUnsignedLongLongSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewIntegerUnsignedLongLong); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //unsigned long long + wColDesc.itemCount = 2; + wColDesc.separator = 0; + wColDesc.data.itemSize = Qword; + wColDesc.data.qwordMode = UnsignedDecQword; + appendResetDescriptor(8 + charwidth * 41, tr("Unsigned long long (64-bit)"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::integerHexShortSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewIntegerHexShort); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //hex short + wColDesc.itemCount = 8; + wColDesc.separator = 0; + wColDesc.data.itemSize = Word; + wColDesc.data.wordMode = HexWord; + appendResetDescriptor(8 + charwidth * 39, tr("Hex short (16-bit)"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::integerHexLongSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewIntegerHexLong); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //hex long + wColDesc.itemCount = 4; + wColDesc.separator = 0; + wColDesc.data.itemSize = Dword; + wColDesc.data.dwordMode = HexDword; + appendResetDescriptor(8 + charwidth * 35, tr("Hex long (32-bit)"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::integerHexLongLongSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewIntegerHexLongLong); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //hex long long + wColDesc.itemCount = 2; + wColDesc.separator = 0; + wColDesc.data.itemSize = Qword; + wColDesc.data.qwordMode = HexQword; + appendResetDescriptor(8 + charwidth * 33, tr("Hex long long (64-bit)"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::floatFloatSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewFloatFloat); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //float dword + wColDesc.itemCount = 4; + wColDesc.separator = 0; + wColDesc.data.itemSize = Dword; + wColDesc.data.dwordMode = FloatDword; + appendResetDescriptor(8 + charwidth * 55, tr("Float (32-bit)"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::floatDoubleSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewFloatDouble); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //float qword + wColDesc.itemCount = 2; + wColDesc.separator = 0; + wColDesc.data.itemSize = Qword; + wColDesc.data.qwordMode = DoubleQword; + appendResetDescriptor(8 + charwidth * 47, tr("Double (64-bit)"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::floatLongDoubleSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewFloatLongDouble); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //float qword + wColDesc.itemCount = 2; + wColDesc.separator = 0; + wColDesc.data.itemSize = Tword; + wColDesc.data.twordMode = FloatTword; + appendResetDescriptor(8 + charwidth * 59, tr("Long double (80-bit)"), false, wColDesc); + + wColDesc.isData = false; //empty column + wColDesc.itemCount = 0; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, "", false, wColDesc); + + reloadData(); +} + +void TraceDump::addressAsciiSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewAddressAscii); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //void* + wColDesc.itemCount = 1; + wColDesc.separator = 0; +#ifdef _WIN64 + wColDesc.data.itemSize = Qword; + wColDesc.data.qwordMode = HexQword; +#else + wColDesc.data.itemSize = Dword; + wColDesc.data.dwordMode = HexDword; +#endif + appendResetDescriptor(8 + charwidth * 2 * sizeof(duint), tr("Value"), false, wColDesc); + + wColDesc.isData = true; + wColDesc.separator = 0; +#ifdef _WIN64 + wColDesc.itemCount = 8; +#else + wColDesc.itemCount = 4; +#endif + wColDesc.data.itemSize = Byte; + wColDesc.data.byteMode = AsciiByte; + wColDesc.columnSwitch = [this]() + { + this->setView(ViewAddressUnicode); + }; + appendDescriptor(8 + charwidth * wColDesc.itemCount, tr("ASCII"), true, wColDesc); + + wColDesc.isData = false; //comments + wColDesc.itemCount = 1; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, tr("Comments"), false, wColDesc); + + reloadData(); +} + +void TraceDump::addressUnicodeSlot() +{ + Config()->setUint("HexDump", "DefaultView", (duint)ViewAddressUnicode); + int charwidth = getCharWidth(); + ColumnDescriptor wColDesc; + DataDescriptor dDesc; + + wColDesc.isData = true; //void* + wColDesc.itemCount = 1; + wColDesc.separator = 0; +#ifdef _WIN64 + wColDesc.data.itemSize = Qword; + wColDesc.data.qwordMode = HexQword; +#else + wColDesc.data.itemSize = Dword; + wColDesc.data.dwordMode = HexDword; +#endif + appendResetDescriptor(8 + charwidth * 2 * sizeof(duint), tr("Value"), false, wColDesc); + + wColDesc.isData = true; + wColDesc.separator = 0; +#ifdef _WIN64 + wColDesc.itemCount = 4; +#else + wColDesc.itemCount = 2; +#endif + wColDesc.data.itemSize = Word; + wColDesc.data.wordMode = UnicodeWord; + wColDesc.columnSwitch = [this]() + { + this->setView(ViewAddressAscii); + }; + appendDescriptor(8 + charwidth * wColDesc.itemCount, tr("UNICODE"), true, wColDesc); + + wColDesc.isData = false; //comments + wColDesc.itemCount = 1; + wColDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + wColDesc.data = dDesc; + appendDescriptor(0, tr("Comments"), false, wColDesc); + + reloadData(); +} + +void TraceDump::disassemblySlot() +{ + SELECTIONDATA selection; + selectionGet(&selection); + emit showDisassemblyTab(selection.start, selection.end, rvaToVa(getTableOffsetRva())); +} + +void TraceDump::selectionGet(SELECTIONDATA* selection) +{ + selection->start = rvaToVa(getSelectionStart()); + selection->end = rvaToVa(getSelectionEnd()); + Bridge::getBridge()->setResult(BridgeResult::SelectionGet, 1); +} + +void TraceDump::selectionSet(const SELECTIONDATA* selection) +{ + dsint selMin = mMemPage->getBase(); + dsint selMax = selMin + mMemPage->getSize(); + dsint start = selection->start; + dsint end = selection->end; + if(start < selMin || start >= selMax || end < selMin || end >= selMax) //selection out of range + { + Bridge::getBridge()->setResult(BridgeResult::SelectionSet, 0); + return; + } + setSingleSelection(start - selMin); + expandSelectionUpTo(end - selMin); + reloadData(); + Bridge::getBridge()->setResult(BridgeResult::SelectionSet, 1); +} + +void TraceDump::findReferencesSlot() +{ + //TODO + //QString addrStart = ToPtrString(rvaToVa(getSelectionStart())); + //QString addrEnd = ToPtrString(rvaToVa(getSelectionEnd())); + //QString addrDisasm = ToPtrString(mDisas->rvaToVa(mDisas->getSelectionStart())); + //DbgCmdExec(QString("findrefrange " + addrStart + ", " + addrEnd + ", " + addrDisasm)); + //emit displayReferencesWidget(); +} + +void TraceDump::binaryEditSlot() +{ + HexEditDialog hexEdit(this); + dsint selStart = getSelectionStart(); + dsint selSize = getSelectionEnd() - selStart + 1; + byte_t* data = new byte_t[selSize]; + mMemPage->read(data, selStart, selSize); + hexEdit.mHexEdit->setData(QByteArray((const char*)data, selSize)); + delete [] data; + hexEdit.setWindowTitle(tr("Edit data at %1").arg(ToPtrString(rvaToVa(selStart)))); + if(hexEdit.exec() != QDialog::Accepted) + return; + dsint dataSize = hexEdit.mHexEdit->data().size(); + dsint newSize = selSize > dataSize ? selSize : dataSize; + data = new byte_t[newSize]; + mMemPage->read(data, selStart, newSize); + QByteArray patched = hexEdit.mHexEdit->applyMaskedData(QByteArray((const char*)data, newSize)); + mMemPage->write(patched.constData(), selStart, patched.size()); + GuiUpdateAllViews(); +} + +void TraceDump::binaryCopySlot() +{ + HexEditDialog hexEdit(this); + dsint selStart = getSelectionStart(); + dsint selSize = getSelectionEnd() - selStart + 1; + byte_t* data = new byte_t[selSize]; + mMemPage->read(data, selStart, selSize); + hexEdit.mHexEdit->setData(QByteArray((const char*)data, selSize)); + delete [] data; + Bridge::CopyToClipboard(hexEdit.mHexEdit->pattern(true)); +} + +void TraceDump::binarySaveToFileSlot() +{ + QString fileName = QFileDialog::getSaveFileName(this, tr("Save to file"), QDir::currentPath(), tr("All files (*.*)")); + if(fileName.length()) + { + // Get starting selection and selection size, then convert selStart to VA + dsint selStart = getSelectionStart(); + dsint selSize = getSelectionEnd() - selStart + 1; + + // Prepare command + fileName = QDir::toNativeSeparators(fileName); + QString cmd = QString("savedata \"%1\",%2,%3").arg(fileName, ToHexString(rvaToVa(selStart)), ToHexString(selSize)); + DbgCmdExec(cmd); + } +} + +void TraceDump::findPattern() +{ + HexEditDialog hexEdit(this); + hexEdit.showEntireBlock(true); + hexEdit.isDataCopiable(false); + hexEdit.mHexEdit->setOverwriteMode(false); + hexEdit.setWindowTitle(tr("Find Pattern...")); + if(hexEdit.exec() != QDialog::Accepted) + return; + dsint addr = rvaToVa(getSelectionStart()); + if(hexEdit.entireBlock()) + addr = DbgMemFindBaseAddr(addr, 0); + QString addrText = ToPtrString(addr); + DbgCmdExec(QString("findall " + addrText + ", " + hexEdit.mHexEdit->pattern() + ", &data&")); + emit displayReferencesWidget(); +} + +void TraceDump::copyFileOffsetSlot() +{ + duint addr = rvaToVa(getInitialSelection()); + duint offset = DbgFunctions()->VaToFileOffset(addr); + if(offset) + { + QString addrText = ToHexString(offset); + Bridge::CopyToClipboard(addrText); + } + else + QMessageBox::warning(this, tr("Error!"), tr("Selection not in a file...")); +} + +void TraceDump::undoSelectionSlot() +{ + dsint start = rvaToVa(getSelectionStart()); + dsint end = rvaToVa(getSelectionEnd()); + if(!DbgFunctions()->PatchInRange(start, end)) //nothing patched in selected range + return; + DbgFunctions()->PatchRestoreRange(start, end); + reloadData(); +} + +void TraceDump::selectionUpdatedSlot() +{ + QString selStart = ToPtrString(rvaToVa(getSelectionStart())); + QString selEnd = ToPtrString(rvaToVa(getSelectionEnd())); + QString info = tr("Dump"); + char mod[MAX_MODULE_SIZE] = ""; + if(DbgFunctions()->ModNameFromAddr(rvaToVa(getSelectionStart()), mod, true)) + info = QString(mod) + ""; + GuiAddStatusBarMessage(QString(info + ": " + selStart + " -> " + selEnd + QString().sprintf(" (0x%.8X bytes)\n", getSelectionEnd() - getSelectionStart() + 1)).toUtf8().constData()); +} + +void TraceDump::syncWithExpressionSlot() +{ + if(!DbgIsDebugging()) + return; + GotoDialog gotoDialog(this, true); + gotoDialog.setWindowTitle(tr("Enter expression to sync with...")); + gotoDialog.setInitialExpression(mSyncAddrExpression); + if(gotoDialog.exec() != QDialog::Accepted) + return; + mSyncAddrExpression = gotoDialog.expressionText; + updateDumpSlot(); +} + +void TraceDump::allocMemorySlot() +{ + WordEditDialog mLineEdit(this); + mLineEdit.setup(tr("Size"), 0x1000, sizeof(duint)); + if(mLineEdit.exec() == QDialog::Accepted) + { + duint memsize = mLineEdit.getVal(); + if(memsize == 0) // 1GB + { + SimpleWarningBox(this, tr("Warning"), tr("You're trying to allocate a zero-sized buffer just now.")); + return; + } + if(memsize > 1024 * 1024 * 1024) + { + SimpleErrorBox(this, tr("Error"), tr("The size of buffer you're trying to allocate exceeds 1GB. Please check your expression to ensure nothing is wrong.")); + return; + } + DbgCmdExecDirect(QString("alloc %1").arg(ToPtrString(memsize))); + duint addr = DbgValFromString("$result"); + if(addr != 0) + { + DbgCmdExec("Dump $result"); + } + else + { + SimpleErrorBox(this, tr("Error"), tr("Memory allocation failed!")); + return; + } + } +} + +void TraceDump::setView(ViewEnum_t view) +{ + switch(view) + { + case ViewHexAscii: + hexAsciiSlot(); + break; + case ViewHexUnicode: + hexUnicodeSlot(); + break; + case ViewTextAscii: + textAsciiSlot(); + break; + case ViewTextUnicode: + textUnicodeSlot(); + break; + case ViewIntegerSignedByte: + integerSignedByteSlot(); + break; + case ViewIntegerSignedShort: + integerSignedShortSlot(); + break; + case ViewIntegerSignedLong: + integerSignedLongSlot(); + break; + case ViewIntegerSignedLongLong: + integerSignedLongLongSlot(); + break; + case ViewIntegerUnsignedByte: + integerUnsignedByteSlot(); + break; + case ViewIntegerUnsignedShort: + integerUnsignedShortSlot(); + break; + case ViewIntegerUnsignedLong: + integerUnsignedLongSlot(); + break; + case ViewIntegerUnsignedLongLong: + integerUnsignedLongLongSlot(); + break; + case ViewIntegerHexShort: + integerHexShortSlot(); + break; + case ViewIntegerHexLong: + integerHexLongSlot(); + break; + case ViewIntegerHexLongLong: + integerHexLongLongSlot(); + break; + case ViewFloatFloat: + floatFloatSlot(); + break; + case ViewFloatDouble: + floatDoubleSlot(); + break; + case ViewFloatLongDouble: + floatLongDoubleSlot(); + break; + case ViewAddress: + case ViewAddressAscii: + addressAsciiSlot(); + break; + case ViewAddressUnicode: + addressUnicodeSlot(); + break; + case ViewHexCodepage: + hexLastCodepageSlot(); + break; + case ViewTextCodepage: + textLastCodepageSlot(); + break; + default: + hexAsciiSlot(); + break; + } +} + +void TraceDump::headerButtonReleasedSlot(int colIndex) +{ + auto callback = mDescriptor[colIndex].columnSwitch; + if(callback) + callback(); +} diff --git a/src/gui/Src/Tracer/TraceDump.h b/src/gui/Src/Tracer/TraceDump.h new file mode 100644 index 00000000..48f0743e --- /dev/null +++ b/src/gui/Src/Tracer/TraceDump.h @@ -0,0 +1,128 @@ +#pragma once + +#include "HexDump.h" +#include "TraceFileDump.h" + +//forward declaration +//class CPUMultiDump; +class TraceBrowser; +class GotoDialog; +class CommonActions; + +class TraceDump : public HexDump +{ + Q_OBJECT +public: + explicit TraceDump(TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent); + void getColumnRichText(int col, dsint rva, RichTextPainter::List & richText) override; + QString paintContent(QPainter* painter, dsint rowBase, int rowOffset, int col, int x, int y, int w, int h); + void setupContextMenu(); + void getAttention(); + void contextMenuEvent(QContextMenuEvent* event); + void mouseDoubleClickEvent(QMouseEvent* event); + void mouseMoveEvent(QMouseEvent* event); + +signals: + void displayReferencesWidget(); + void showDisassemblyTab(duint selectionStart, duint selectionEnd, duint firstAddress); + +public slots: + void modifyValueSlot(); + void gotoExpressionSlot(); + void gotoFileOffsetSlot(); + void gotoStartSlot(); + void gotoEndSlot(); + void gotoPreviousReferenceSlot(); + void gotoNextReferenceSlot(); + + void hexAsciiSlot(); + void hexUnicodeSlot(); + void hexCodepageSlot(); + void hexLastCodepageSlot(); + + void textAsciiSlot(); + void textUnicodeSlot(); + void textCodepageSlot(); + void textLastCodepageSlot(); + + void integerSignedByteSlot(); + void integerSignedShortSlot(); + void integerSignedLongSlot(); + void integerSignedLongLongSlot(); + void integerUnsignedByteSlot(); + void integerUnsignedShortSlot(); + void integerUnsignedLongSlot(); + void integerUnsignedLongLongSlot(); + void integerHexShortSlot(); + void integerHexLongSlot(); + void integerHexLongLongSlot(); + + void floatFloatSlot(); + void floatDoubleSlot(); + void floatLongDoubleSlot(); + + void addressUnicodeSlot(); + void addressAsciiSlot(); + void disassemblySlot(); + + void selectionGet(SELECTIONDATA* selection); + void selectionSet(const SELECTIONDATA* selection); + + void binaryEditSlot(); + void binaryCopySlot(); + void binarySaveToFileSlot(); + void findPattern(); + void copyFileOffsetSlot(); + void undoSelectionSlot(); + void findReferencesSlot(); + + void selectionUpdatedSlot(); + void syncWithExpressionSlot(); + void allocMemorySlot(); + + void headerButtonReleasedSlot(int colIndex); + +private: + TraceFileDumpMemoryPage* mMemoryPage; + MenuBuilder* mMenuBuilder; + CommonActions* mCommonActions; + + //QMenu* mPluginMenu; + //QMenu* mFollowInDumpMenu; + QList mFollowInDumpActions; + + GotoDialog* mGoto = nullptr; + GotoDialog* mGotoOffset = nullptr; + TraceBrowser* mDisas; + //CPUMultiDump* mMultiDump; + int mAsciiSeparator = 0; + + enum ViewEnum_t + { + ViewHexAscii = 0, + ViewHexUnicode, + ViewTextAscii, + ViewTextUnicode, + ViewIntegerSignedShort, + ViewIntegerSignedLong, + ViewIntegerSignedLongLong, + ViewIntegerUnsignedShort, + ViewIntegerUnsignedLong, + ViewIntegerUnsignedLongLong, + ViewIntegerHexShort, + ViewIntegerHexLong, + ViewIntegerHexLongLong, + ViewFloatFloat, + ViewFloatDouble, + ViewFloatLongDouble, + ViewAddress, + ViewIntegerSignedByte, + ViewIntegerUnsignedByte, + ViewAddressAscii, + ViewAddressUnicode, + ViewHexCodepage, + ViewTextCodepage + }; + + void setView(ViewEnum_t view); +}; diff --git a/src/gui/Src/Tracer/TraceFileDump.cpp b/src/gui/Src/Tracer/TraceFileDump.cpp index 2068d854..a8bed95c 100644 --- a/src/gui/Src/Tracer/TraceFileDump.cpp +++ b/src/gui/Src/Tracer/TraceFileDump.cpp @@ -13,7 +13,7 @@ TraceFileDump::~TraceFileDump() void TraceFileDump::clear() { - maxIndex = 0; + maxIndex = 0ull; dump.clear(); } @@ -150,3 +150,41 @@ void TraceFileDump::findMemAreas() } while(true); } + +// TraceFileDumpMemoryPage +TraceFileDumpMemoryPage::TraceFileDumpMemoryPage(QObject* parent) : MemoryPage(0, 0, parent) +{ + dump = nullptr; +} + +void TraceFileDumpMemoryPage::setSelectedIndex(unsigned long long index) +{ + if(dump) + selectedIndex = std::min(index, dump->getMaxIndex()); + else + selectedIndex = 0ull; +} + +void TraceFileDumpMemoryPage::setDumpObject(TraceFileDump* dump) +{ + this->dump = dump; +} + +unsigned long long TraceFileDumpMemoryPage::getSelectedIndex() const +{ + return selectedIndex; +} + +bool TraceFileDumpMemoryPage::read(void* parDest, dsint parRVA, duint parSize) const +{ + if(!dump) + return false; + auto buffer = dump->getBytes(mBase + parRVA, parSize, selectedIndex); + memcpy(parDest, buffer.data(), parSize); + return true; +} + +bool TraceFileDumpMemoryPage::write(const void* parDest, dsint parRVA, duint parSize) +{ + return false; // write is not supported +} diff --git a/src/gui/Src/Tracer/TraceFileDump.h b/src/gui/Src/Tracer/TraceFileDump.h index b1a3a8c4..28efbddb 100644 --- a/src/gui/Src/Tracer/TraceFileDump.h +++ b/src/gui/Src/Tracer/TraceFileDump.h @@ -2,6 +2,7 @@ #include "Imports.h" #include +#include "MemoryPage.h" class TraceFileDump { @@ -49,3 +50,18 @@ private: std::map dump; unsigned long long maxIndex; }; + +class TraceFileDumpMemoryPage : public MemoryPage +{ + Q_OBJECT +public: + TraceFileDumpMemoryPage(QObject* parent = 0); + virtual bool read(void* parDest, dsint parRVA, duint parSize) const override; + virtual bool write(const void* parDest, dsint parRVA, duint parSize) override; + void setSelectedIndex(unsigned long long index); + unsigned long long getSelectedIndex() const; + void setDumpObject(TraceFileDump* dump); +private: + TraceFileDump* dump; + unsigned long long selectedIndex = 0ull; +}; diff --git a/src/gui/Src/Tracer/TraceFileReader.cpp b/src/gui/Src/Tracer/TraceFileReader.cpp index 11f7ebcb..0dd018bf 100644 --- a/src/gui/Src/Tracer/TraceFileReader.cpp +++ b/src/gui/Src/Tracer/TraceFileReader.cpp @@ -123,6 +123,11 @@ unsigned long long TraceFileReader::Length() const return length; } +TraceFileDump* TraceFileReader::getDump() +{ + return &dump; +} + QString TraceFileReader::getIndexText(unsigned long long index) const { QString indexString; diff --git a/src/gui/Src/Tracer/TraceFileReader.h b/src/gui/Src/Tracer/TraceFileReader.h index 25effd5c..86fb6d9c 100644 --- a/src/gui/Src/Tracer/TraceFileReader.h +++ b/src/gui/Src/Tracer/TraceFileReader.h @@ -43,6 +43,7 @@ public: void buildDumpTo(unsigned long long index); std::vector getReferences(duint startAddr, duint endAddr) const; void debugdump(unsigned long long index); + TraceFileDump* getDump(); signals: void parseFinished(); diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index 35ac6874..f7b52136 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -2,6 +2,7 @@ #include "ui_TraceWidget.h" #include "TraceBrowser.h" #include "TraceInfoBox.h" +#include "TraceDump.h" #include "TraceFileReader.h" #include "TraceRegisters.h" #include "StdTable.h" @@ -16,6 +17,8 @@ TraceWidget::TraceWidget(QWidget* parent) : mTraceWidget = new TraceBrowser(this); mOverview = new StdTable(this); mInfo = new TraceInfoBox(this); + mMemoryPage = new TraceFileDumpMemoryPage(this); + mDump = new TraceDump(mTraceWidget, mMemoryPage, this); mGeneralRegs = new TraceRegisters(this); //disasm ui->mTopLeftUpperRightFrameLayout->addWidget(mTraceWidget); @@ -44,7 +47,12 @@ TraceWidget::TraceWidget(QWidget* parent) : ui->mTopHSplitter->setCollapsible(1, true); // allow collapsing the RegisterView //info - ui->mTopLeftLowerFrameLayout->addWidget(mInfo); + //ui->mTopLeftLowerFrameLayout->addWidget(mInfo); + ui->mTopLeftUpperRightFrameLayout->addWidget(mInfo); + + //dump + ui->mTopLeftLowerFrameLayout->addWidget(mDump); + int height = (mInfo->getRowHeight() + 1) * 4; ui->mTopLeftLowerFrame->setMinimumHeight(height + 2); ui->mTopHSplitter->setSizes(QList({1000, 1})); @@ -80,10 +88,14 @@ void TraceWidget::traceSelectionChanged(unsigned long long selection) { registers = traceFile->Registers(selection); mInfo->update(selection, traceFile, registers); + traceFile->buildDumpTo(selection); + mMemoryPage->setDumpObject(traceFile->getDump()); } else memset(®isters, 0, sizeof(registers)); } + else + mMemoryPage->setDumpObject(nullptr); mGeneralRegs->setRegisters(®isters); } diff --git a/src/gui/Src/Tracer/TraceWidget.h b/src/gui/Src/Tracer/TraceWidget.h index ba59653a..948ea120 100644 --- a/src/gui/Src/Tracer/TraceWidget.h +++ b/src/gui/Src/Tracer/TraceWidget.h @@ -8,7 +8,9 @@ class CPUWidget; class TraceRegisters; class TraceBrowser; class TraceFileReader; +class TraceFileDumpMemoryPage; class TraceInfoBox; +class TraceDump; class StdTable; namespace Ui @@ -33,7 +35,9 @@ protected slots: protected: TraceBrowser* mTraceWidget; TraceInfoBox* mInfo; + TraceDump* mDump; TraceRegisters* mGeneralRegs; + TraceFileDumpMemoryPage* mMemoryPage; StdTable* mOverview; private: diff --git a/src/gui/Src/Tracer/TraceWidget.ui b/src/gui/Src/Tracer/TraceWidget.ui index baf6db2e..41a887de 100644 --- a/src/gui/Src/Tracer/TraceWidget.ui +++ b/src/gui/Src/Tracer/TraceWidget.ui @@ -14,24 +14,6 @@ Form - - 0 - - - QLayout::SetMaximumSize - - - 0 - - - 0 - - - 0 - - - 0 - @@ -54,12 +36,6 @@ false - - - 0 - 0 - - Qt::Vertical @@ -67,40 +43,45 @@ 1 - true + false - - - QFrame::NoFrame + + + Qt::Horizontal - - QFrame::Raised + + 1 - - - 0 + + false + + + + QFrame::NoFrame - - 0 + + QFrame::Raised - - 0 - - - 0 - - - 0 - - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + - - - 0 - 0 - - QFrame::NoFrame @@ -123,16 +104,13 @@ 0 + + + - - - 0 - 0 - - Qt::Vertical @@ -143,19 +121,13 @@ false - - - 0 - 0 - - QFrame::NoFrame QFrame::Raised - + 0 @@ -171,41 +143,87 @@ 0 + + + - - - 0 - 0 - - QFrame::NoFrame QFrame::Raised - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - + + + + + + + Qt::Horizontal + + + 1 + + + false + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + QFrame::NoFrame + + + QFrame::Raised + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + diff --git a/src/gui/x64dbg.pro b/src/gui/x64dbg.pro index aac3d062..0665df4b 100644 --- a/src/gui/x64dbg.pro +++ b/src/gui/x64dbg.pro @@ -80,6 +80,7 @@ SOURCES += \ Src/Gui/RichTextItemDelegate.cpp \ Src/Gui/SystemBreakpointScriptDialog.cpp \ Src/Imports.cpp \ + Src/Tracer/TraceDump.cpp \ Src/Tracer/TraceFileDump.cpp \ Src/Tracer/TraceInfoBox.cpp \ Src/Tracer/TraceRegisters.cpp \ @@ -203,6 +204,7 @@ HEADERS += \ Src/Gui/CPURegistersView.h \ Src/Gui/RichTextItemDelegate.h \ Src/Gui/SystemBreakpointScriptDialog.h \ + Src/Tracer/TraceDump.h \ Src/Tracer/TraceFileDump.h \ Src/Tracer/TraceInfoBox.h \ Src/Tracer/TraceRegisters.h \