From d5384d78eb2532b6692958969e83e3e31a0a184c Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Thu, 18 May 2023 20:45:43 +0800 Subject: [PATCH 01/33] Introduced dump to trace --- src/gui/Src/Tracer/TraceBrowser.cpp | 9 +- src/gui/Src/Tracer/TraceBrowser.h | 2 + src/gui/Src/Tracer/TraceFileDump.cpp | 131 +++++++++++++++++++++++++ src/gui/Src/Tracer/TraceFileDump.h | 50 ++++++++++ src/gui/Src/Tracer/TraceFileReader.cpp | 49 +++++++++ src/gui/Src/Tracer/TraceFileReader.h | 6 ++ src/gui/Src/Tracer/TraceFileSearch.cpp | 2 +- src/gui/x64dbg.pro | 2 + 8 files changed, 249 insertions(+), 2 deletions(-) create mode 100644 src/gui/Src/Tracer/TraceFileDump.cpp create mode 100644 src/gui/Src/Tracer/TraceFileDump.h diff --git a/src/gui/Src/Tracer/TraceBrowser.cpp b/src/gui/Src/Tracer/TraceBrowser.cpp index 0c8a46bdd0..0f775f9874 100644 --- a/src/gui/Src/Tracer/TraceBrowser.cpp +++ b/src/gui/Src/Tracer/TraceBrowser.cpp @@ -959,7 +959,8 @@ void TraceBrowser::setupRightClickContextMenu() mRvaDisplayEnabled = false; for(int i = 0; i < MemoryOperandsCount; i++) { - menu->addAction(QString("%1: %2 -> %3").arg(getAddrText(MemoryAddress[i], nolabel, false)).arg(ToPtrString(MemoryOldContent[i])).arg(ToPtrString(MemoryNewContent[i]))); + auto action = menu->addAction(QString("%1: %2 -> %3").arg(getAddrText(MemoryAddress[i], nolabel, false)).arg(ToPtrString(MemoryOldContent[i])).arg(ToPtrString(MemoryNewContent[i]))); + connect(action, SIGNAL(triggered()), this, SLOT(debugdump())); } mRvaDisplayEnabled = RvaDisplayEnabled; return true; @@ -1880,3 +1881,9 @@ void TraceBrowser::gotoIndexSlot(duint index) { disasm(index, false); } + +void TraceBrowser::debugdump() +{ + mTraceFile->buildDumpTo(getInitialSelection()); + mTraceFile->debugdump(getInitialSelection()); +} diff --git a/src/gui/Src/Tracer/TraceBrowser.h b/src/gui/Src/Tracer/TraceBrowser.h index b60e9d146d..d3243bd67c 100644 --- a/src/gui/Src/Tracer/TraceBrowser.h +++ b/src/gui/Src/Tracer/TraceBrowser.h @@ -187,6 +187,8 @@ public slots: void synchronizeCpuSlot(); void gotoIndexSlot(duint index); + void debugdump(); + protected: void disasm(unsigned long long index, bool history = true); }; diff --git a/src/gui/Src/Tracer/TraceFileDump.cpp b/src/gui/Src/Tracer/TraceFileDump.cpp new file mode 100644 index 0000000000..cc6dd76eff --- /dev/null +++ b/src/gui/Src/Tracer/TraceFileDump.cpp @@ -0,0 +1,131 @@ +#include "TraceFileDump.h" +#include "StringUtil.h" + +TraceFileDump::TraceFileDump() +{ + maxIndex = 0ull; +} + +TraceFileDump::~TraceFileDump() +{ + +} + +void TraceFileDump::clear() +{ + maxIndex = 0; + dump.clear(); +} + +unsigned char TraceFileDump::getByte(Key location, bool & success) const +{ + auto it = dump.lower_bound(location); + if(it != dump.end()) + { + if(it->first.addr == location.addr) + { + success = true; + if(location.index > it->first.index) + { + return it->second.newData; + } + else + { + return it->second.oldData; + } + } + else if(it != dump.begin()) + { + // try to get to next record which may hold the required data + --it; + if(it->first.addr == location.addr) + { + success = true; + if(location.index > it->first.index) + { + return it->second.newData; + } + else + { + return it->second.oldData; + } + } + } + } + success = false; + return 0; +} + +std::vector TraceFileDump::getBytes(duint addr, duint size, unsigned long long index) const +{ + std::vector buffer; + buffer.resize(size); + for(duint i = 0; i < size; i++) + { + bool success; + buffer[i] = getByte({addr + i, index}, success); + } + return buffer; +} + +//void TraceFileDump::addMemAccess(duint addr, DumpRecord record) +//{ +// Key location = {addr, maxIndex}; +// dump.insert(std::make_pair(location, record)); +//} + +void TraceFileDump::addMemAccess(duint addr, const void* oldData, const void* newData, size_t size) +{ + std::vector> records; + records.resize(size); + // insert in the correct order + for(size_t i = size; i > 0; i--) + { + auto b = size - i; + records[i - 1].first.addr = addr + b; + records[i - 1].first.index = maxIndex; + records[i - 1].second.oldData = ((const unsigned char*)oldData)[b]; + records[i - 1].second.newData = ((const unsigned char*)newData)[b]; + records[i - 1].second.isWrite = 0; //TODO + records[i - 1].second.isExecute = 0; + } + dump.insert(records.begin(), records.end()); +} + +// Find continuous memory areas. It is done separate from adding memory accesses because the number of addresses is less than that of memory accesses +// TODO: We also need another findMemAreas() which only updates incrementally, when the user steps while tracing +void TraceFileDump::findMemAreas() +{ + memAreas.clear(); + if(dump.empty()) + return; + duint addr = dump.begin()->first.addr; //highest address + duint end = addr; + duint start; + // find first access to addr + do + { + auto it = dump.lower_bound({addr - 1, maxIndex}); + // try to find out if addr-1 is in the dump + for(; it != dump.end(); it = dump.lower_bound({addr - 1, maxIndex})) + { + if(it->first.addr != addr - 1) + break; + addr--; + } + // addr-1 is not in the dump, insert the memory area + start = addr; + memAreas.push_back(std::make_pair(start, end)); + // get to next lowest address + if(it != dump.end()) + { + addr = it->first.addr; + end = addr; + } + else + { + break; + } + } + while(true); +} diff --git a/src/gui/Src/Tracer/TraceFileDump.h b/src/gui/Src/Tracer/TraceFileDump.h new file mode 100644 index 0000000000..b6245a91ef --- /dev/null +++ b/src/gui/Src/Tracer/TraceFileDump.h @@ -0,0 +1,50 @@ +#pragma once + +#include "Imports.h" +#include + +class TraceFileDump +{ +public: + struct Key + { + duint addr; + unsigned long long index; + friend bool operator <(const Key & a, const Key & b) + { + // order is inverted, highest address is less! We want to use lower_bound() to find last memory access index. + return a.addr > b.addr || a.addr == b.addr && a.index > b.index; + } + }; + struct DumpRecord + { + unsigned char oldData; + unsigned char newData; + unsigned char isWrite; + unsigned char isExecute; + }; + + TraceFileDump(); + ~TraceFileDump(); + void clear(); + // Read a byte at "addr" at the moment given in "index" + unsigned char getByte(Key location, bool & success) const; + std::vector getBytes(duint addr, duint size, unsigned long long index) const; + // Insert a memory access record + //void addMemAccess(duint addr, DumpRecord record); + void addMemAccess(duint addr, const void* oldData, const void* newData, size_t size); + inline void increaseIndex() + { + maxIndex++; + } + inline unsigned long long getMaxIndex() + { + return maxIndex; + } + // Find continuous memory areas + void findMemAreas(); + std::vector> memAreas; +private: + std::map dump; + unsigned long long maxIndex; +}; diff --git a/src/gui/Src/Tracer/TraceFileReader.cpp b/src/gui/Src/Tracer/TraceFileReader.cpp index 82aa10cf2a..43de66e0f0 100644 --- a/src/gui/Src/Tracer/TraceFileReader.cpp +++ b/src/gui/Src/Tracer/TraceFileReader.cpp @@ -36,6 +36,7 @@ bool TraceFileReader::Open(const QString & fileName) parser->wait(); } error = true; + dump.clear(); traceFile.setFileName(fileName); traceFile.open(QFile::ReadOnly); if(traceFile.isReadable()) @@ -97,6 +98,7 @@ void TraceFileReader::parseFinishedSlot() progress.store(0); delete parser; parser = nullptr; + buildDump(0); // initialize dump with first instruction emit parseFinished(); //for(auto i : fileIndex) @@ -570,6 +572,53 @@ void TraceFileReader::purgeLastPage() } } +void TraceFileReader::buildDump(unsigned long long index) +{ + int memoryCount = MemoryAccessCount(index); + //Zydis disas; + unsigned char opcode[MAX_DISASM_BUFFER]; + int opcodeSize; + OpCode(index, opcode, &opcodeSize); + dump.addMemAccess(Registers(index).regcontext.cip, opcode, opcode, opcodeSize); + //disas.Disassemble(Registers(index).regcontext.cip, opcode, opcodeSize); + duint oldMemory[32]; + duint newMemory[32]; + duint address[32]; + bool isValid[32]; + MemoryAccessInfo(index, address, oldMemory, newMemory, isValid); + for(int i = 0; i < memoryCount; i++) + { + //TODO: disassemble to find out the size of memory operand! + dump.addMemAccess(address[i], &oldMemory[i], &newMemory[i], sizeof(duint)); + } +} + +void TraceFileReader::buildDumpTo(unsigned long long index) +{ + auto start = dump.getMaxIndex(); + for(auto i = start + 1; i <= index; i++) + { + dump.increaseIndex(); + buildDump(i); + } +} + +void TraceFileReader::debugdump(unsigned long long index) +{ + dump.findMemAreas(); + for(auto c : dump.memAreas) + { + auto mData = dump.getBytes(c.first, c.second - c.first + 1, index); + QString data; + for(size_t i = 0; i < mData.size(); i++) + { + byte_t ch = mData.at(i); + data += QString().sprintf("%02X", ch); + } + GuiAddLogMessage(QString("dump:%1-%2:%3\n").arg(ToPtrString(c.first)).arg(ToPtrString(c.second)).arg(data).toUtf8()); + } +} + //TraceFilePage TraceFilePage::TraceFilePage(TraceFileReader* parent, unsigned long long fileOffset, unsigned long long maxLength) { diff --git a/src/gui/Src/Tracer/TraceFileReader.h b/src/gui/Src/Tracer/TraceFileReader.h index 3e392ff717..18480b886e 100644 --- a/src/gui/Src/Tracer/TraceFileReader.h +++ b/src/gui/Src/Tracer/TraceFileReader.h @@ -3,6 +3,7 @@ #include "Bridge.h" #include #include +#include "TraceFileDump.h" class TraceFileParser; class TraceFilePage; @@ -38,6 +39,10 @@ class TraceFileReader : public QObject void purgeLastPage(); + void buildDump(unsigned long long index); + void buildDumpTo(unsigned long long index); + void debugdump(unsigned long long index); + signals: void parseFinished(); @@ -72,6 +77,7 @@ private slots: TraceFileParser* parser; std::map pages; TraceFilePage* getPage(unsigned long long index, unsigned long long* base); + TraceFileDump dump; QBeaEngine* mDisasm; }; diff --git a/src/gui/Src/Tracer/TraceFileSearch.cpp b/src/gui/Src/Tracer/TraceFileSearch.cpp index 0222fc031f..03796538a9 100644 --- a/src/gui/Src/Tracer/TraceFileSearch.cpp +++ b/src/gui/Src/Tracer/TraceFileSearch.cpp @@ -91,7 +91,7 @@ int TraceFileSearchMemReference(TraceFileReader* file, duint address) { int count = 0; Zydis zy; - GuiReferenceInitialize(QCoreApplication::translate("TraceFileSearch", "Reference").toUtf8().constData()); + GuiReferenceInitialize(QCoreApplication::translate("TraceFileSearch", "Reference").append(' ').append(ToPtrString(address)).toUtf8().constData()); GuiReferenceAddColumn(sizeof(duint) * 2, QCoreApplication::translate("TraceFileSearch", "Address").toUtf8().constData()); GuiReferenceAddColumn(5, QCoreApplication::translate("TraceFileSearch", "Index").toUtf8().constData()); GuiReferenceAddColumn(100, QCoreApplication::translate("TraceFileSearch", "Disassembly").toUtf8().constData()); diff --git a/src/gui/x64dbg.pro b/src/gui/x64dbg.pro index 124f818332..aac3d062c9 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/TraceFileDump.cpp \ Src/Tracer/TraceInfoBox.cpp \ Src/Tracer/TraceRegisters.cpp \ Src/Tracer/TraceWidget.cpp \ @@ -202,6 +203,7 @@ HEADERS += \ Src/Gui/CPURegistersView.h \ Src/Gui/RichTextItemDelegate.h \ Src/Gui/SystemBreakpointScriptDialog.h \ + Src/Tracer/TraceFileDump.h \ Src/Tracer/TraceInfoBox.h \ Src/Tracer/TraceRegisters.h \ Src/Tracer/TraceWidget.h \ From 5adac838a7a9b89f850e01540202f3ca7128da77 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Wed, 7 Jun 2023 12:31:11 +0800 Subject: [PATCH 02/33] Disassemble to get correct memory operand size --- src/gui/Src/Tracer/TraceBrowser.cpp | 8 +- src/gui/Src/Tracer/TraceBrowser.h | 1 + src/gui/Src/Tracer/TraceFileDump.cpp | 30 ++--- src/gui/Src/Tracer/TraceFileReader.cpp | 172 ++++++++++++++++++++++++- src/gui/Src/Tracer/TraceFileReader.h | 3 + src/gui/Src/Tracer/TraceInfoBox.cpp | 140 +------------------- 6 files changed, 191 insertions(+), 163 deletions(-) diff --git a/src/gui/Src/Tracer/TraceBrowser.cpp b/src/gui/Src/Tracer/TraceBrowser.cpp index 0f775f9874..219569fbb5 100644 --- a/src/gui/Src/Tracer/TraceBrowser.cpp +++ b/src/gui/Src/Tracer/TraceBrowser.cpp @@ -1839,8 +1839,10 @@ void TraceBrowser::searchConstantSlot() constantDlg.setup(tr("Constant"), initialConstant, sizeof(duint)); if(constantDlg.exec() == QDialog::Accepted) { - TraceFileSearchConstantRange(mTraceFile, constantDlg.getVal(), constantDlg.getVal()); + auto ticks = GetTickCount(); + int count = TraceFileSearchConstantRange(mTraceFile, constantDlg.getVal(), constantDlg.getVal()); emit displayReferencesWidget(); + GuiAddLogMessage(tr("%1 result(s) in %2ms\n").arg(count).arg(GetTickCount() - ticks).toUtf8().constData()); } } @@ -1850,8 +1852,10 @@ void TraceBrowser::searchMemRefSlot() memRefDlg.setup(tr("References"), 0, sizeof(duint)); if(memRefDlg.exec() == QDialog::Accepted) { - TraceFileSearchMemReference(mTraceFile, memRefDlg.getVal()); + auto ticks = GetTickCount(); + int count = TraceFileSearchMemReference(mTraceFile, memRefDlg.getVal()); emit displayReferencesWidget(); + GuiAddLogMessage(tr("%1 result(s) in %2ms\n").arg(count).arg(GetTickCount() - ticks).toUtf8().constData()); } } diff --git a/src/gui/Src/Tracer/TraceBrowser.h b/src/gui/Src/Tracer/TraceBrowser.h index d3243bd67c..bf7d49ee1e 100644 --- a/src/gui/Src/Tracer/TraceBrowser.h +++ b/src/gui/Src/Tracer/TraceBrowser.h @@ -192,3 +192,4 @@ public slots: protected: void disasm(unsigned long long index, bool history = true); }; + diff --git a/src/gui/Src/Tracer/TraceFileDump.cpp b/src/gui/Src/Tracer/TraceFileDump.cpp index cc6dd76eff..1ccd1a30a9 100644 --- a/src/gui/Src/Tracer/TraceFileDump.cpp +++ b/src/gui/Src/Tracer/TraceFileDump.cpp @@ -24,15 +24,7 @@ unsigned char TraceFileDump::getByte(Key location, bool & success) const { if(it->first.addr == location.addr) { - success = true; - if(location.index > it->first.index) - { - return it->second.newData; - } - else - { - return it->second.oldData; - } + goto found; } else if(it != dump.begin()) { @@ -40,20 +32,22 @@ unsigned char TraceFileDump::getByte(Key location, bool & success) const --it; if(it->first.addr == location.addr) { - success = true; - if(location.index > it->first.index) - { - return it->second.newData; - } - else - { - return it->second.oldData; - } + goto found; } } } success = false; return 0; +found: + success = true; + if(location.index > it->first.index) + { + return it->second.newData; + } + else + { + return it->second.oldData; + } } std::vector TraceFileDump::getBytes(duint addr, duint size, unsigned long long index) const diff --git a/src/gui/Src/Tracer/TraceFileReader.cpp b/src/gui/Src/Tracer/TraceFileReader.cpp index 43de66e0f0..d835d6d2e2 100644 --- a/src/gui/Src/Tracer/TraceFileReader.cpp +++ b/src/gui/Src/Tracer/TraceFileReader.cpp @@ -574,22 +574,47 @@ void TraceFileReader::purgeLastPage() void TraceFileReader::buildDump(unsigned long long index) { - int memoryCount = MemoryAccessCount(index); - //Zydis disas; + int MemoryOperandsCount = MemoryAccessCount(index); + if(MemoryOperandsCount == 0) //LEA and NOP instructions + return; + Zydis zydis; unsigned char opcode[MAX_DISASM_BUFFER]; int opcodeSize; + REGDUMP registers = Registers(index);; OpCode(index, opcode, &opcodeSize); - dump.addMemAccess(Registers(index).regcontext.cip, opcode, opcode, opcodeSize); - //disas.Disassemble(Registers(index).regcontext.cip, opcode, opcodeSize); + dump.addMemAccess(registers.regcontext.cip, opcode, opcode, opcodeSize); + zydis.Disassemble(registers.regcontext.cip, opcode, opcodeSize); duint oldMemory[32]; duint newMemory[32]; duint address[32]; bool isValid[32]; + bool used[32]; MemoryAccessInfo(index, address, oldMemory, newMemory, isValid); - for(int i = 0; i < memoryCount; i++) + memset(used, 0, sizeof(used)); + for(int opindex = 0; opindex < zydis.OpCount(); opindex++) { - //TODO: disassemble to find out the size of memory operand! - dump.addMemAccess(address[i], &oldMemory[i], &newMemory[i], sizeof(duint)); + size_t value = zydis.ResolveOpValue(opindex, [®isters](ZydisRegister reg) + { + return resolveZydisRegister(registers, reg); + }); + if(zydis[opindex].type == ZYDIS_OPERAND_TYPE_MEMORY) + { + int size; + size = ceil(zydis[opindex].size / 8.0); + bool found = false; + for(int i = 0; i < MemoryOperandsCount; i++) + { + // TODO: fix up FS/GS segment + if(address[i] != value) + continue; + dump.addMemAccess(address[i], &oldMemory[i], &newMemory[i], size); + found = true; + break; + } + //if(!found) + //bug??? + //GuiAddLogMessage(QString("buildDump bug %1???\n").arg(index).toUtf8().constData()); + } } } @@ -798,3 +823,136 @@ void TraceFilePage::updateInstructions() { instructions.clear(); } + +duint resolveZydisRegister(const REGDUMP & registers, ZydisRegister regname) +{ + switch(regname) + { +#ifdef _WIN64 + case ZYDIS_REGISTER_RAX: + return registers.regcontext.cax; + case ZYDIS_REGISTER_RCX: + return registers.regcontext.ccx; + case ZYDIS_REGISTER_RDX: + return registers.regcontext.cdx; + case ZYDIS_REGISTER_RBX: + return registers.regcontext.cbx; + case ZYDIS_REGISTER_RSP: + return registers.regcontext.csp; + case ZYDIS_REGISTER_RBP: + return registers.regcontext.cbp; + case ZYDIS_REGISTER_RSI: + return registers.regcontext.csi; + case ZYDIS_REGISTER_RDI: + return registers.regcontext.cdi; + case ZYDIS_REGISTER_R8: + return registers.regcontext.r8; + case ZYDIS_REGISTER_R9: + return registers.regcontext.r9; + case ZYDIS_REGISTER_R10: + return registers.regcontext.r10; + case ZYDIS_REGISTER_R11: + return registers.regcontext.r11; + case ZYDIS_REGISTER_R12: + return registers.regcontext.r12; + case ZYDIS_REGISTER_R13: + return registers.regcontext.r13; + case ZYDIS_REGISTER_R14: + return registers.regcontext.r14; + case ZYDIS_REGISTER_R15: + return registers.regcontext.r15; + case ZYDIS_REGISTER_R8D: + return registers.regcontext.r8 & 0xFFFFFFFF; + case ZYDIS_REGISTER_R9D: + return registers.regcontext.r9 & 0xFFFFFFFF; + case ZYDIS_REGISTER_R10D: + return registers.regcontext.r10 & 0xFFFFFFFF; + case ZYDIS_REGISTER_R11D: + return registers.regcontext.r11 & 0xFFFFFFFF; + case ZYDIS_REGISTER_R12D: + return registers.regcontext.r12 & 0xFFFFFFFF; + case ZYDIS_REGISTER_R13D: + return registers.regcontext.r13 & 0xFFFFFFFF; + case ZYDIS_REGISTER_R15D: + return registers.regcontext.r15 & 0xFFFFFFFF; + case ZYDIS_REGISTER_R8W: + return registers.regcontext.r8 & 0xFFFF; + case ZYDIS_REGISTER_R9W: + return registers.regcontext.r9 & 0xFFFF; + case ZYDIS_REGISTER_R10W: + return registers.regcontext.r10 & 0xFFFF; + case ZYDIS_REGISTER_R11W: + return registers.regcontext.r11 & 0xFFFF; + case ZYDIS_REGISTER_R12W: + return registers.regcontext.r12 & 0xFFFF; + case ZYDIS_REGISTER_R13W: + return registers.regcontext.r13 & 0xFFFF; + case ZYDIS_REGISTER_R15W: + return registers.regcontext.r15 & 0xFFFF; + case ZYDIS_REGISTER_R8B: + return registers.regcontext.r8 & 0xFF; + case ZYDIS_REGISTER_R9B: + return registers.regcontext.r9 & 0xFF; + case ZYDIS_REGISTER_R10B: + return registers.regcontext.r10 & 0xFF; + case ZYDIS_REGISTER_R11B: + return registers.regcontext.r11 & 0xFF; + case ZYDIS_REGISTER_R12B: + return registers.regcontext.r12 & 0xFF; + case ZYDIS_REGISTER_R13B: + return registers.regcontext.r13 & 0xFF; + case ZYDIS_REGISTER_R15B: + return registers.regcontext.r15 & 0xFF; +#endif //_WIN64 + case ZYDIS_REGISTER_EAX: + return registers.regcontext.cax & 0xFFFFFFFF; + case ZYDIS_REGISTER_ECX: + return registers.regcontext.ccx & 0xFFFFFFFF; + case ZYDIS_REGISTER_EDX: + return registers.regcontext.cdx & 0xFFFFFFFF; + case ZYDIS_REGISTER_EBX: + return registers.regcontext.cbx & 0xFFFFFFFF; + case ZYDIS_REGISTER_ESP: + return registers.regcontext.csp & 0xFFFFFFFF; + case ZYDIS_REGISTER_EBP: + return registers.regcontext.cbp & 0xFFFFFFFF; + case ZYDIS_REGISTER_ESI: + return registers.regcontext.csi & 0xFFFFFFFF; + case ZYDIS_REGISTER_EDI: + return registers.regcontext.cdi & 0xFFFFFFFF; + case ZYDIS_REGISTER_AX: + return registers.regcontext.cax & 0xFFFF; + case ZYDIS_REGISTER_CX: + return registers.regcontext.ccx & 0xFFFF; + case ZYDIS_REGISTER_DX: + return registers.regcontext.cdx & 0xFFFF; + case ZYDIS_REGISTER_BX: + return registers.regcontext.cbx & 0xFFFF; + case ZYDIS_REGISTER_SP: + return registers.regcontext.csp & 0xFFFF; + case ZYDIS_REGISTER_BP: + return registers.regcontext.cbp & 0xFFFF; + case ZYDIS_REGISTER_SI: + return registers.regcontext.csi & 0xFFFF; + case ZYDIS_REGISTER_DI: + return registers.regcontext.cdi & 0xFFFF; + case ZYDIS_REGISTER_AL: + return registers.regcontext.cax & 0xFF; + case ZYDIS_REGISTER_CL: + return registers.regcontext.ccx & 0xFF; + case ZYDIS_REGISTER_DL: + return registers.regcontext.cdx & 0xFF; + case ZYDIS_REGISTER_BL: + return registers.regcontext.cbx & 0xFF; + case ZYDIS_REGISTER_AH: + return (registers.regcontext.cax & 0xFF00) >> 8; + case ZYDIS_REGISTER_CH: + return (registers.regcontext.ccx & 0xFF00) >> 8; + case ZYDIS_REGISTER_DH: + return (registers.regcontext.cdx & 0xFF00) >> 8; + case ZYDIS_REGISTER_BH: + return (registers.regcontext.cbx & 0xFF00) >> 8; + default: + return static_cast(0); + } +}; diff --git a/src/gui/Src/Tracer/TraceFileReader.h b/src/gui/Src/Tracer/TraceFileReader.h index 18480b886e..785bd38879 100644 --- a/src/gui/Src/Tracer/TraceFileReader.h +++ b/src/gui/Src/Tracer/TraceFileReader.h @@ -4,6 +4,7 @@ #include #include #include "TraceFileDump.h" +#include "zydis_wrapper.h" class TraceFileParser; class TraceFilePage; @@ -81,3 +82,5 @@ private slots: QBeaEngine* mDisasm; }; + +duint resolveZydisRegister(const REGDUMP & registers, ZydisRegister reg); diff --git a/src/gui/Src/Tracer/TraceInfoBox.cpp b/src/gui/Src/Tracer/TraceInfoBox.cpp index b84c2d246c..2d15f3de97 100644 --- a/src/gui/Src/Tracer/TraceInfoBox.cpp +++ b/src/gui/Src/Tracer/TraceInfoBox.cpp @@ -33,138 +33,6 @@ void TraceInfoBox::update(unsigned long long selection, TraceFileReader* traceFi int opsize; traceFile->OpCode(selection, opcode, &opsize); clear(); - auto resolveRegValue = [®isters](ZydisRegister regname) - { - switch(regname) - { -#ifdef _WIN64 - case ZYDIS_REGISTER_RAX: - return registers.regcontext.cax; - case ZYDIS_REGISTER_RCX: - return registers.regcontext.ccx; - case ZYDIS_REGISTER_RDX: - return registers.regcontext.cdx; - case ZYDIS_REGISTER_RBX: - return registers.regcontext.cbx; - case ZYDIS_REGISTER_RSP: - return registers.regcontext.csp; - case ZYDIS_REGISTER_RBP: - return registers.regcontext.cbp; - case ZYDIS_REGISTER_RSI: - return registers.regcontext.csi; - case ZYDIS_REGISTER_RDI: - return registers.regcontext.cdi; - case ZYDIS_REGISTER_R8: - return registers.regcontext.r8; - case ZYDIS_REGISTER_R9: - return registers.regcontext.r9; - case ZYDIS_REGISTER_R10: - return registers.regcontext.r10; - case ZYDIS_REGISTER_R11: - return registers.regcontext.r11; - case ZYDIS_REGISTER_R12: - return registers.regcontext.r12; - case ZYDIS_REGISTER_R13: - return registers.regcontext.r13; - case ZYDIS_REGISTER_R14: - return registers.regcontext.r14; - case ZYDIS_REGISTER_R15: - return registers.regcontext.r15; - case ZYDIS_REGISTER_R8D: - return registers.regcontext.r8 & 0xFFFFFFFF; - case ZYDIS_REGISTER_R9D: - return registers.regcontext.r9 & 0xFFFFFFFF; - case ZYDIS_REGISTER_R10D: - return registers.regcontext.r10 & 0xFFFFFFFF; - case ZYDIS_REGISTER_R11D: - return registers.regcontext.r11 & 0xFFFFFFFF; - case ZYDIS_REGISTER_R12D: - return registers.regcontext.r12 & 0xFFFFFFFF; - case ZYDIS_REGISTER_R13D: - return registers.regcontext.r13 & 0xFFFFFFFF; - case ZYDIS_REGISTER_R15D: - return registers.regcontext.r15 & 0xFFFFFFFF; - case ZYDIS_REGISTER_R8W: - return registers.regcontext.r8 & 0xFFFF; - case ZYDIS_REGISTER_R9W: - return registers.regcontext.r9 & 0xFFFF; - case ZYDIS_REGISTER_R10W: - return registers.regcontext.r10 & 0xFFFF; - case ZYDIS_REGISTER_R11W: - return registers.regcontext.r11 & 0xFFFF; - case ZYDIS_REGISTER_R12W: - return registers.regcontext.r12 & 0xFFFF; - case ZYDIS_REGISTER_R13W: - return registers.regcontext.r13 & 0xFFFF; - case ZYDIS_REGISTER_R15W: - return registers.regcontext.r15 & 0xFFFF; - case ZYDIS_REGISTER_R8B: - return registers.regcontext.r8 & 0xFF; - case ZYDIS_REGISTER_R9B: - return registers.regcontext.r9 & 0xFF; - case ZYDIS_REGISTER_R10B: - return registers.regcontext.r10 & 0xFF; - case ZYDIS_REGISTER_R11B: - return registers.regcontext.r11 & 0xFF; - case ZYDIS_REGISTER_R12B: - return registers.regcontext.r12 & 0xFF; - case ZYDIS_REGISTER_R13B: - return registers.regcontext.r13 & 0xFF; - case ZYDIS_REGISTER_R15B: - return registers.regcontext.r15 & 0xFF; -#endif //_WIN64 - case ZYDIS_REGISTER_EAX: - return registers.regcontext.cax & 0xFFFFFFFF; - case ZYDIS_REGISTER_ECX: - return registers.regcontext.ccx & 0xFFFFFFFF; - case ZYDIS_REGISTER_EDX: - return registers.regcontext.cdx & 0xFFFFFFFF; - case ZYDIS_REGISTER_EBX: - return registers.regcontext.cbx & 0xFFFFFFFF; - case ZYDIS_REGISTER_ESP: - return registers.regcontext.csp & 0xFFFFFFFF; - case ZYDIS_REGISTER_EBP: - return registers.regcontext.cbp & 0xFFFFFFFF; - case ZYDIS_REGISTER_ESI: - return registers.regcontext.csi & 0xFFFFFFFF; - case ZYDIS_REGISTER_EDI: - return registers.regcontext.cdi & 0xFFFFFFFF; - case ZYDIS_REGISTER_AX: - return registers.regcontext.cax & 0xFFFF; - case ZYDIS_REGISTER_CX: - return registers.regcontext.ccx & 0xFFFF; - case ZYDIS_REGISTER_DX: - return registers.regcontext.cdx & 0xFFFF; - case ZYDIS_REGISTER_BX: - return registers.regcontext.cbx & 0xFFFF; - case ZYDIS_REGISTER_SP: - return registers.regcontext.csp & 0xFFFF; - case ZYDIS_REGISTER_BP: - return registers.regcontext.cbp & 0xFFFF; - case ZYDIS_REGISTER_SI: - return registers.regcontext.csi & 0xFFFF; - case ZYDIS_REGISTER_DI: - return registers.regcontext.cdi & 0xFFFF; - case ZYDIS_REGISTER_AL: - return registers.regcontext.cax & 0xFF; - case ZYDIS_REGISTER_CL: - return registers.regcontext.ccx & 0xFF; - case ZYDIS_REGISTER_DL: - return registers.regcontext.cdx & 0xFF; - case ZYDIS_REGISTER_BL: - return registers.regcontext.cbx & 0xFF; - case ZYDIS_REGISTER_AH: - return (registers.regcontext.cax & 0xFF00) >> 8; - case ZYDIS_REGISTER_CH: - return (registers.regcontext.ccx & 0xFF00) >> 8; - case ZYDIS_REGISTER_DH: - return (registers.regcontext.cdx & 0xFF00) >> 8; - case ZYDIS_REGISTER_BH: - return (registers.regcontext.cbx & 0xFF00) >> 8; - default: - return static_cast(0); - } - }; duint MemoryAddress[MAX_MEMORY_OPERANDS]; duint MemoryOldContent[MAX_MEMORY_OPERANDS]; duint MemoryNewContent[MAX_MEMORY_OPERANDS]; @@ -195,7 +63,10 @@ void TraceInfoBox::update(unsigned long long selection, TraceFileReader* traceFi QString registerLine, memoryLine; for(opindex = 0; opindex < zydis.OpCount(); opindex++) { - size_t value = zydis.ResolveOpValue(opindex, resolveRegValue); + size_t value = zydis.ResolveOpValue(opindex, [®isters](ZydisRegister reg) + { + return resolveZydisRegister(registers, reg); + }); if(zydis[opindex].type == ZYDIS_OPERAND_TYPE_MEMORY) { if(!memoryLine.isEmpty()) @@ -218,7 +89,6 @@ void TraceInfoBox::update(unsigned long long selection, TraceFileReader* traceFi { // Double precision #ifdef _WIN64 - //TODO: Untested for(memaccessindex = 0; memaccessindex < MemoryOperandsCount; memaccessindex++) { if(MemoryAddress[memaccessindex] == value) @@ -253,7 +123,6 @@ void TraceInfoBox::update(unsigned long long selection, TraceFileReader* traceFi else if(zydis[opindex].size == 32 && zydis.getVectorElementType(opindex) == Zydis::VETFloat32) { // Single precision - //TODO: Untested for(memaccessindex = 0; memaccessindex < MemoryOperandsCount; memaccessindex++) { if(MemoryAddress[memaccessindex] == value) @@ -306,7 +175,6 @@ void TraceInfoBox::update(unsigned long long selection, TraceFileReader* traceFi } else if(registerName >= ZYDIS_REGISTER_YMM0 && registerName <= ArchValue(ZYDIS_REGISTER_YMM7, ZYDIS_REGISTER_YMM15)) { - //TODO: Untested registerLine += CPUInfoBox::formatSSEOperand(QByteArray((const char*)®isters.regcontext.YmmRegisters[registerName - ZYDIS_REGISTER_XMM0], 32), zydis.getVectorElementType(opindex)); } else From f3d0f9a278a08a240b064f96e7fda8fcc6e64da7 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Sun, 11 Jun 2023 12:18:54 +0800 Subject: [PATCH 03/33] Use trace file dump index to accelerate memory reference search --- src/gui/Src/Tracer/TraceFileDump.cpp | 31 +++++++- src/gui/Src/Tracer/TraceFileDump.h | 1 + src/gui/Src/Tracer/TraceFileReader.cpp | 7 +- src/gui/Src/Tracer/TraceFileReader.h | 3 +- src/gui/Src/Tracer/TraceFileSearch.cpp | 99 +++++++++++++++++++------- 5 files changed, 112 insertions(+), 29 deletions(-) diff --git a/src/gui/Src/Tracer/TraceFileDump.cpp b/src/gui/Src/Tracer/TraceFileDump.cpp index 1ccd1a30a9..2068d854c0 100644 --- a/src/gui/Src/Tracer/TraceFileDump.cpp +++ b/src/gui/Src/Tracer/TraceFileDump.cpp @@ -62,6 +62,33 @@ std::vector TraceFileDump::getBytes(duint addr, duint size, unsig return buffer; } +// find references to the memory address +std::vector TraceFileDump::getReferences(duint startAddr, duint endAddr) const +{ + std::vector index; + if(endAddr < startAddr) + std::swap(endAddr, startAddr); + // find references to the memory address + auto it = dump.lower_bound({endAddr, maxIndex + 1}); + while(it != dump.end() && it->first.addr >= startAddr && it->first.addr <= endAddr) + { + index.push_back(it->first.index); + ++it; + } + if(index.empty()) + return index; + // rearrange the array and remove duplicates + std::sort(index.begin(), index.end()); + std::vector result; + result.push_back(index[0]); + for(size_t i = 1; i < index.size(); i++) + { + if(index[i] != result[result.size() - 1]) + result.push_back(index[i]); + } + return result; +} + //void TraceFileDump::addMemAccess(duint addr, DumpRecord record) //{ // Key location = {addr, maxIndex}; @@ -99,9 +126,9 @@ void TraceFileDump::findMemAreas() // find first access to addr do { - auto it = dump.lower_bound({addr - 1, maxIndex}); + auto it = dump.lower_bound({addr - 1, maxIndex + 1}); // try to find out if addr-1 is in the dump - for(; it != dump.end(); it = dump.lower_bound({addr - 1, maxIndex})) + for(; it != dump.end(); it = dump.lower_bound({addr - 1, maxIndex + 1})) { if(it->first.addr != addr - 1) break; diff --git a/src/gui/Src/Tracer/TraceFileDump.h b/src/gui/Src/Tracer/TraceFileDump.h index b6245a91ef..b1a3a8c4d3 100644 --- a/src/gui/Src/Tracer/TraceFileDump.h +++ b/src/gui/Src/Tracer/TraceFileDump.h @@ -30,6 +30,7 @@ class TraceFileDump // Read a byte at "addr" at the moment given in "index" unsigned char getByte(Key location, bool & success) const; std::vector getBytes(duint addr, duint size, unsigned long long index) const; + std::vector getReferences(duint startAddr, duint endAddr) const; // Insert a memory access record //void addMemAccess(duint addr, DumpRecord record); void addMemAccess(duint addr, const void* oldData, const void* newData, size_t size); diff --git a/src/gui/Src/Tracer/TraceFileReader.cpp b/src/gui/Src/Tracer/TraceFileReader.cpp index d835d6d2e2..11f7ebcb08 100644 --- a/src/gui/Src/Tracer/TraceFileReader.cpp +++ b/src/gui/Src/Tracer/TraceFileReader.cpp @@ -621,7 +621,7 @@ void TraceFileReader::buildDump(unsigned long long index) void TraceFileReader::buildDumpTo(unsigned long long index) { auto start = dump.getMaxIndex(); - for(auto i = start + 1; i <= index; i++) + for(auto i = start + 1; i < index; i++) { dump.increaseIndex(); buildDump(i); @@ -644,6 +644,11 @@ void TraceFileReader::debugdump(unsigned long long index) } } +std::vector TraceFileReader::getReferences(duint startAddr, duint endAddr) const +{ + return dump.getReferences(startAddr, endAddr); +} + //TraceFilePage TraceFilePage::TraceFilePage(TraceFileReader* parent, unsigned long long fileOffset, unsigned long long maxLength) { diff --git a/src/gui/Src/Tracer/TraceFileReader.h b/src/gui/Src/Tracer/TraceFileReader.h index 785bd38879..25effd5c10 100644 --- a/src/gui/Src/Tracer/TraceFileReader.h +++ b/src/gui/Src/Tracer/TraceFileReader.h @@ -40,8 +40,8 @@ class TraceFileReader : public QObject void purgeLastPage(); - void buildDump(unsigned long long index); void buildDumpTo(unsigned long long index); + std::vector getReferences(duint startAddr, duint endAddr) const; void debugdump(unsigned long long index); signals: @@ -79,6 +79,7 @@ private slots: std::map pages; TraceFilePage* getPage(unsigned long long index, unsigned long long* base); TraceFileDump dump; + void buildDump(unsigned long long index); QBeaEngine* mDisasm; }; diff --git a/src/gui/Src/Tracer/TraceFileSearch.cpp b/src/gui/Src/Tracer/TraceFileSearch.cpp index 03796538a9..ce0ea20b84 100644 --- a/src/gui/Src/Tracer/TraceFileSearch.cpp +++ b/src/gui/Src/Tracer/TraceFileSearch.cpp @@ -97,37 +97,86 @@ int TraceFileSearchMemReference(TraceFileReader* file, duint address) GuiReferenceAddColumn(100, QCoreApplication::translate("TraceFileSearch", "Disassembly").toUtf8().constData()); GuiReferenceAddCommand(QCoreApplication::translate("TraceFileSearch", "Follow index in trace").toUtf8().constData(), "gototrace 0x$1"); GuiReferenceSetRowCount(0); + bool useTraceDump = true; - for(unsigned long long index = 0; index < file->Length(); index++) + if(useTraceDump) { - bool found = false; - //Memory - duint memAddr[MAX_MEMORY_OPERANDS]; - duint memOldContent[MAX_MEMORY_OPERANDS]; - duint memNewContent[MAX_MEMORY_OPERANDS]; - bool isValid[MAX_MEMORY_OPERANDS]; - int memAccessCount = file->MemoryAccessCount(index); - if(memAccessCount > 0) + if(file->Length() > 0) { - file->MemoryAccessInfo(index, memAddr, memOldContent, memNewContent, isValid); - for(int i = 0; i < memAccessCount; i++) + file->buildDumpTo(file->Length() - 1); + auto results = file->getReferences(address, address + sizeof(duint) - 1); + for(size_t i = 0; i < results.size(); i++) { - found |= inRange(memAddr[i], address, address + sizeof(duint) - 1); + bool found = false; + unsigned long long index = results[i]; + //Memory + duint memAddr[MAX_MEMORY_OPERANDS]; + duint memOldContent[MAX_MEMORY_OPERANDS]; + duint memNewContent[MAX_MEMORY_OPERANDS]; + bool isValid[MAX_MEMORY_OPERANDS]; + int memAccessCount = file->MemoryAccessCount(index); + if(memAccessCount > 0) + { + file->MemoryAccessInfo(index, memAddr, memOldContent, memNewContent, isValid); + for(int i = 0; i < memAccessCount; i++) + { + found |= inRange(memAddr[i], address, address + sizeof(duint) - 1); + } + //Constants: TO DO + //Populate reference view + if(found) + { + GuiReferenceSetRowCount(count + 1); + GuiReferenceSetCellContent(count, 0, ToPtrString(file->Registers(index).regcontext.cip).toUtf8().constData()); + GuiReferenceSetCellContent(count, 1, file->getIndexText(index).toUtf8().constData()); + unsigned char opcode[16]; + int opcodeSize = 0; + file->OpCode(index, opcode, &opcodeSize); + zy.Disassemble(file->Registers(index).regcontext.cip, opcode, opcodeSize); + GuiReferenceSetCellContent(count, 2, zy.InstructionText(true).c_str()); + //GuiReferenceSetCurrentTaskProgress; GuiReferenceSetProgress + count++; + } + } } - //Constants: TO DO - //Populate reference view - if(found) + } + else + count = 0; + return count; + } + else + { + for(unsigned long long index = 0; index < file->Length(); index++) + { + bool found = false; + //Memory + duint memAddr[MAX_MEMORY_OPERANDS]; + duint memOldContent[MAX_MEMORY_OPERANDS]; + duint memNewContent[MAX_MEMORY_OPERANDS]; + bool isValid[MAX_MEMORY_OPERANDS]; + int memAccessCount = file->MemoryAccessCount(index); + if(memAccessCount > 0) { - GuiReferenceSetRowCount(count + 1); - GuiReferenceSetCellContent(count, 0, ToPtrString(file->Registers(index).regcontext.cip).toUtf8().constData()); - GuiReferenceSetCellContent(count, 1, file->getIndexText(index).toUtf8().constData()); - unsigned char opcode[16]; - int opcodeSize = 0; - file->OpCode(index, opcode, &opcodeSize); - zy.Disassemble(file->Registers(index).regcontext.cip, opcode, opcodeSize); - GuiReferenceSetCellContent(count, 2, zy.InstructionText(true).c_str()); - //GuiReferenceSetCurrentTaskProgress; GuiReferenceSetProgress - count++; + file->MemoryAccessInfo(index, memAddr, memOldContent, memNewContent, isValid); + for(int i = 0; i < memAccessCount; i++) + { + found |= inRange(memAddr[i], address, address + sizeof(duint) - 1); + } + //Constants: TO DO + //Populate reference view + if(found) + { + GuiReferenceSetRowCount(count + 1); + GuiReferenceSetCellContent(count, 0, ToPtrString(file->Registers(index).regcontext.cip).toUtf8().constData()); + GuiReferenceSetCellContent(count, 1, file->getIndexText(index).toUtf8().constData()); + unsigned char opcode[16]; + int opcodeSize = 0; + file->OpCode(index, opcode, &opcodeSize); + zy.Disassemble(file->Registers(index).regcontext.cip, opcode, opcodeSize); + GuiReferenceSetCellContent(count, 2, zy.InstructionText(true).c_str()); + //GuiReferenceSetCurrentTaskProgress; GuiReferenceSetProgress + count++; + } } } } From 226efe3ea1dc4b1175f013e63ccbadad57ce0942 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Thu, 27 Jul 2023 17:31:49 +0800 Subject: [PATCH 04/33] Added trace dump to trace widget --- 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 | 1401 ++++++++++++++++++++++++ src/gui/Src/Tracer/TraceDump.h | 124 +++ src/gui/Src/Tracer/TraceFileDump.cpp | 50 +- src/gui/Src/Tracer/TraceFileDump.h | 19 + src/gui/Src/Tracer/TraceFileReader.cpp | 5 + src/gui/Src/Tracer/TraceFileReader.h | 1 + src/gui/Src/Tracer/TraceInfoBox.cpp | 18 +- src/gui/Src/Tracer/TraceInfoBox.h | 1 + src/gui/Src/Tracer/TraceWidget.cpp | 21 +- src/gui/Src/Tracer/TraceWidget.h | 4 + src/gui/Src/Tracer/TraceWidget.ui | 161 ++- src/gui/x64dbg.pro | 2 + 15 files changed, 1764 insertions(+), 58 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 9505e192b5..cc31789b0f 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 bc428c10ec..4f403cde4a 100644 --- a/src/gui/Src/BasicView/HexDump.h +++ b/src/gui/Src/BasicView/HexDump.h @@ -79,7 +79,7 @@ class HexDump : public AbstractTableView 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 01213b7430..e6a5bb50ce 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 0000000000..3a6cd98d55 --- /dev/null +++ b/src/gui/Src/Tracer/TraceDump.cpp @@ -0,0 +1,1401 @@ +#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, [this](QMenu*) + { + return mMemoryPage->isAvailable(); + }); + + mCommonActions = new CommonActions(this, getActionHelperFuncs(), [this]() + { + return rvaToVa(getSelectionStart()); + }); + + MenuBuilder* wBinaryMenu = new MenuBuilder(this); + wBinaryMenu->addAction(makeShortcutAction(DIcon("binary_copy"), tr("&Copy"), SLOT(binaryCopySlot()), "ActionBinaryCopy")); + 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); + auto wIsValidReadPtrCallback = [this](QMenu*) + { + duint ptr = 0; + DbgMemRead(rvaToVa(getSelectionStart()), (unsigned char*)&ptr, sizeof(duint)); + return DbgMemIsValidReadPtr(ptr); + }; + + 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")); + + 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(); + }); + 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 || !mMemoryPage->isAvailable()) + 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; + } +} + +#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::gotoExpressionSlot() +{ + if(!mMemoryPage->isAvailable()) + return; + if(!mGoto) + mGoto = new GotoDialog(this, false, true); + 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()); + GuiAddLogMessage(ToPtrString(value).toUtf8()); + this->printDumpAt(value, true); + } +} + +void TraceDump::gotoFileOffsetSlot() +{ + if(!mMemoryPage->isAvailable()) + 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); + this->printDumpAt(value, true); +} + +void TraceDump::gotoStartSlot() +{ + duint dest = mMemPage->getBase(); + this->printDumpAt(dest, true); +} + +void TraceDump::gotoEndSlot() +{ + duint dest = mMemPage->getBase() + mMemPage->getSize() - (getViewableRowsCount() * getBytePerRowCount()); + this->printDumpAt(dest, true); +} + +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::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::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(!mMemoryPage->isAvailable()) + 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::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 0000000000..18bceb00ac --- /dev/null +++ b/src/gui/Src/Tracer/TraceDump.h @@ -0,0 +1,124 @@ +#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 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 binaryCopySlot(); + void binarySaveToFileSlot(); + void findPattern(); + void copyFileOffsetSlot(); + void findReferencesSlot(); + + void selectionUpdatedSlot(); + void syncWithExpressionSlot(); + + 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 2068d854c0..3d96dce55b 100644 --- a/src/gui/Src/Tracer/TraceFileDump.cpp +++ b/src/gui/Src/Tracer/TraceFileDump.cpp @@ -1,3 +1,4 @@ +#include #include "TraceFileDump.h" #include "StringUtil.h" @@ -13,7 +14,7 @@ TraceFileDump::~TraceFileDump() void TraceFileDump::clear() { - maxIndex = 0; + maxIndex = 0ull; dump.clear(); } @@ -150,3 +151,50 @@ void TraceFileDump::findMemAreas() } while(true); } + +// TraceFileDumpMemoryPage +TraceFileDumpMemoryPage::TraceFileDumpMemoryPage(QObject* parent) : MemoryPage(0, 0, parent) +{ + QMutexLocker locker(&lock); + dump = nullptr; +} + +void TraceFileDumpMemoryPage::setSelectedIndex(unsigned long long index) +{ + QMutexLocker locker(&lock); + if(dump) + selectedIndex = std::min(index, dump->getMaxIndex()); + else + selectedIndex = 0ull; +} + +void TraceFileDumpMemoryPage::setDumpObject(TraceFileDump* dump) +{ + QMutexLocker locker(&lock); + this->dump = dump; +} + +bool TraceFileDumpMemoryPage::isAvailable() const +{ + return !!this->dump; +} + +unsigned long long TraceFileDumpMemoryPage::getSelectedIndex() const +{ + return selectedIndex; +} + +bool TraceFileDumpMemoryPage::read(void* parDest, dsint parRVA, duint parSize) const +{ + QMutexLocker locker(&lock); + 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 b1a3a8c4d3..c963ff3aab 100644 --- a/src/gui/Src/Tracer/TraceFileDump.h +++ b/src/gui/Src/Tracer/TraceFileDump.h @@ -2,6 +2,8 @@ #include "Imports.h" #include +#include +#include "MemoryPage.h" class TraceFileDump { @@ -49,3 +51,20 @@ class TraceFileDump 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); + bool isAvailable() const; +private: + TraceFileDump* dump; + mutable QMutex lock; + unsigned long long selectedIndex = 0ull; +}; diff --git a/src/gui/Src/Tracer/TraceFileReader.cpp b/src/gui/Src/Tracer/TraceFileReader.cpp index 11f7ebcb08..0dd018bfd5 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 25effd5c10..86fb6d9c0a 100644 --- a/src/gui/Src/Tracer/TraceFileReader.h +++ b/src/gui/Src/Tracer/TraceFileReader.h @@ -43,6 +43,7 @@ class TraceFileReader : public QObject 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/TraceInfoBox.cpp b/src/gui/Src/Tracer/TraceInfoBox.cpp index 2d15f3de97..5cb010f8a0 100644 --- a/src/gui/Src/Tracer/TraceInfoBox.cpp +++ b/src/gui/Src/Tracer/TraceInfoBox.cpp @@ -6,11 +6,20 @@ TraceInfoBox::TraceInfoBox(TraceWidget* parent) : StdTable(parent) { - addColumnAt(0, "", true); + setWindowTitle("TraceInfoBox"); + enableMultiSelection(false); setShowHeader(false); - clear(); + setRowCount(4); + addColumnAt(0, "", true); + setCellContent(0, 0, ""); + setCellContent(1, 0, ""); + setCellContent(2, 0, ""); + setCellContent(3, 0, ""); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + + setShowHeader(false); + clear(); setMinimumHeight((getRowHeight() + 1) * 4); connect(this, SIGNAL(contextMenuSignal(QPoint)), this, SLOT(contextMenuSlot(QPoint))); @@ -216,6 +225,11 @@ void TraceInfoBox::setupContextMenu() setupShortcuts(); } +int TraceInfoBox::getHeight() +{ + return ((getRowHeight() + 1) * 4); +} + void TraceInfoBox::contextMenuSlot(QPoint pos) { QMenu wMenu(this); //create context menu diff --git a/src/gui/Src/Tracer/TraceInfoBox.h b/src/gui/Src/Tracer/TraceInfoBox.h index c1cbf66a6d..1391f7883f 100644 --- a/src/gui/Src/Tracer/TraceInfoBox.h +++ b/src/gui/Src/Tracer/TraceInfoBox.h @@ -10,6 +10,7 @@ class TraceInfoBox : public StdTable Q_OBJECT public: TraceInfoBox(TraceWidget* parent); + int getHeight(); ~TraceInfoBox(); void update(unsigned long long selection, TraceFileReader* traceFile, const REGDUMP & registers); diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index 35ac687413..d02ab37aba 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); @@ -45,13 +48,15 @@ TraceWidget::TraceWidget(QWidget* parent) : //info ui->mTopLeftLowerFrameLayout->addWidget(mInfo); - int height = (mInfo->getRowHeight() + 1) * 4; + int height = mInfo->getHeight(); ui->mTopLeftLowerFrame->setMinimumHeight(height + 2); - ui->mTopHSplitter->setSizes(QList({1000, 1})); - ui->mTopLeftVSplitter->setSizes(QList({1000, 1})); + + //dump + //ui->mTopLeftLowerFrameLayout->addWidget(mDump); + ui->mBotLeftFrameLayout->addWidget(mDump); //overview - ui->mTopRightLowerFrameLayout->addWidget(mOverview); + ui->mBotRightFrameLayout->addWidget(mOverview); //set up overview mOverview->addColumnAt(0, "", true); @@ -61,7 +66,9 @@ TraceWidget::TraceWidget(QWidget* parent) : mOverview->setCellContent(1, 0, "world"); mOverview->setCellContent(2, 0, "00000000"); mOverview->setCellContent(3, 0, "here we will list all control flow transfers"); - mOverview->hide(); + //mOverview->hide(); + ui->mTopHSplitter->setSizes(QList({1000, 1})); + ui->mTopLeftVSplitter->setSizes(QList({1000, 1})); } TraceWidget::~TraceWidget() @@ -80,10 +87,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 ba59653a41..948ea12037 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 baf6db2e4c..fd966b87d7 100644 --- a/src/gui/Src/Tracer/TraceWidget.ui +++ b/src/gui/Src/Tracer/TraceWidget.ui @@ -54,12 +54,6 @@ false - - - 0 - 0 - - Qt::Vertical @@ -67,36 +61,72 @@ 1 - true + false - - - QFrame::NoFrame + + + Qt::Horizontal - - QFrame::Raised + + 1 - - - 0 - - - 0 + + false + + + + QFrame::NoFrame - - 0 + + QFrame::Raised - - 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + QFrame::NoFrame - - 0 + + QFrame::Raised - + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + - + 0 0 @@ -127,12 +157,6 @@ - - - 0 - 0 - - Qt::Vertical @@ -143,12 +167,6 @@ false - - - 0 - 0 - - QFrame::NoFrame @@ -174,12 +192,6 @@ - - - 0 - 0 - - QFrame::NoFrame @@ -206,6 +218,67 @@ + + + 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 aac3d062c9..0665df4b42 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 \ From 9852b097ccada130c8545dc07625cdee5cba518f Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Sun, 20 Aug 2023 22:16:18 +0800 Subject: [PATCH 05/33] Fixed CustomizeMenuDialog and various features related to modules --- src/gui/Src/BasicView/HexDump.h | 2 +- src/gui/Src/Gui/CustomizeMenuDialog.cpp | 2 + src/gui/Src/Tracer/TraceDump.cpp | 74 ++++++++++++++++++++----- src/gui/Src/Tracer/TraceDump.h | 3 +- src/gui/Src/Tracer/TraceFileDump.cpp | 2 +- src/gui/Src/Utils/Configuration.cpp | 1 + 6 files changed, 67 insertions(+), 17 deletions(-) diff --git a/src/gui/Src/BasicView/HexDump.h b/src/gui/Src/BasicView/HexDump.h index 4f403cde4a..a50824772b 100644 --- a/src/gui/Src/BasicView/HexDump.h +++ b/src/gui/Src/BasicView/HexDump.h @@ -129,7 +129,7 @@ class HexDump : public AbstractTableView void appendResetDescriptor(int width, QString title, bool clickable, ColumnDescriptor descriptor); void clearDescriptors(); - void printDumpAt(dsint parVA, bool select, bool repaint = true, bool updateTableOffset = true); + virtual void printDumpAt(dsint parVA, bool select, bool repaint = true, bool updateTableOffset = true); duint rvaToVa(dsint rva) const; duint getTableOffsetRva() const; diff --git a/src/gui/Src/Gui/CustomizeMenuDialog.cpp b/src/gui/Src/Gui/CustomizeMenuDialog.cpp index 5f88496335..2e16e2b147 100644 --- a/src/gui/Src/Gui/CustomizeMenuDialog.cpp +++ b/src/gui/Src/Gui/CustomizeMenuDialog.cpp @@ -62,6 +62,8 @@ CustomizeMenuDialog::CustomizeMenuDialog(QWidget* parent) : viewName = tr("View"); else if(id == "TraceBrowser") viewName = tr("Trace disassembler"); + else if(id == "TraceDump") + viewName = tr("Trace dump"); else continue; // Add Parent Node diff --git a/src/gui/Src/Tracer/TraceDump.cpp b/src/gui/Src/Tracer/TraceDump.cpp index 3a6cd98d55..3053b8d9af 100644 --- a/src/gui/Src/Tracer/TraceDump.cpp +++ b/src/gui/Src/Tracer/TraceDump.cpp @@ -67,10 +67,10 @@ void TraceDump::setupContextMenu() mMenuBuilder->addMenu(makeMenu(DIcon("copy"), tr("&Copy")), wCopyMenu); - mMenuBuilder->addAction(makeShortcutAction(DIcon("eraser"), tr("&Restore selection"), SLOT(undoSelectionSlot()), "ActionUndoSelection"), [this](QMenu*) + /*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); @@ -154,7 +154,7 @@ void TraceDump::setupContextMenu() 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("fileoffset"), tr("File Offset"), SLOT(gotoFileOffsetSlot()), "ActionGotoFileOffset")); wGotoMenu->addAction(makeShortcutAction(DIcon("top"), tr("Start of Page"), SLOT(gotoStartSlot()), "ActionGotoStart"), [this](QMenu*) { return getSelectionStart() != 0; @@ -235,6 +235,7 @@ void TraceDump::setupContextMenu() //})); mMenuBuilder->loadFromConfig(); + disconnect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(debugStateChanged(DBGSTATE))); updateShortcuts(); } @@ -245,6 +246,48 @@ void TraceDump::getAttention() thread->start(); } +void TraceDump::printDumpAt(dsint parVA, bool select, bool repaint, bool updateTableOffset) +{ + // Modified from Hexdump, removed memory page information + // TODO: get memory range from trace instead + duint wSize; + auto wBase = mMemoryPage->getBase(); + dsint wRVA = parVA - wBase; //calculate rva + int wBytePerRowCount = getBytePerRowCount(); //get the number of bytes per row + dsint wRowCount; + + // Byte offset used to be aligned on the given RVA + mByteOffset = (int)((dsint)wRVA % (dsint)wBytePerRowCount); + mByteOffset = mByteOffset > 0 ? wBytePerRowCount - mByteOffset : 0; + + // Compute row count + wRowCount = wSize / wBytePerRowCount; + wRowCount += mByteOffset > 0 ? 1 : 0; + + //if(mRvaDisplayEnabled && mMemPage->getBase() != mRvaDisplayPageBase) + // mRvaDisplayEnabled = false; + + setRowCount(wRowCount); //set the number of rows + + //mMemPage->setAttributes(wBase, wSize); // Set base and size (Useful when memory page changed) + + if(updateTableOffset) + { + setTableOffset(-1); //make sure the requested address is always first + setTableOffset((wRVA + mByteOffset) / wBytePerRowCount); //change the displayed offset + } + + if(select) + { + setSingleSelection(wRVA); + dsint wEndingAddress = wRVA + getSizeOf(mDescriptor.at(0).data.itemSize) - 1; + expandSelectionUpTo(wEndingAddress); + } + + if(repaint) + reloadData(); +} + void TraceDump::getColumnRichText(int col, dsint rva, RichTextPainter::List & richText) { if(col && !mDescriptor.at(col - 1).isData && mDescriptor.at(col - 1).itemCount) //print comments @@ -256,8 +299,9 @@ void TraceDump::getColumnRichText(int col, dsint rva, RichTextPainter::List & ri mMemPage->read((byte_t*)&data, rva, sizeof(duint)); char modname[MAX_MODULE_SIZE] = ""; - if(!DbgGetModuleAt(data, modname)) - modname[0] = '\0'; + //TODO + //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)) @@ -294,7 +338,7 @@ QString TraceDump::paintContent(QPainter* painter, dsint rowBase, int rowOffset, { // Reset byte offset when base address is reached if(rowBase == 0 && mByteOffset != 0) - printDumpAt(mMemPage->getBase(), false, false); + HexDump::printDumpAt(mMemPage->getBase(), false, false); if(!col) //address { @@ -476,18 +520,19 @@ void TraceDump::gotoExpressionSlot() if(!mMemoryPage->isAvailable()) return; if(!mGoto) - mGoto = new GotoDialog(this, false, true); + mGoto = new GotoDialog(this, false, true, true); 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()); GuiAddLogMessage(ToPtrString(value).toUtf8()); - this->printDumpAt(value, true); + this->HexDump::printDumpAt(value, true); } } -void TraceDump::gotoFileOffsetSlot() +// TODO: Module information need to be read from trace file +/*void TraceDump::gotoFileOffsetSlot() { if(!mMemoryPage->isAvailable()) return; @@ -511,18 +556,18 @@ void TraceDump::gotoFileOffsetSlot() duint value = DbgValFromString(mGotoOffset->expressionText.toUtf8().constData()); value = DbgFunctions()->FileOffsetToVa(modname, value); this->printDumpAt(value, true); -} +}*/ void TraceDump::gotoStartSlot() { duint dest = mMemPage->getBase(); - this->printDumpAt(dest, true); + this->HexDump::printDumpAt(dest, true); } void TraceDump::gotoEndSlot() { duint dest = mMemPage->getBase() + mMemPage->getSize() - (getViewableRowsCount() * getBytePerRowCount()); - this->printDumpAt(dest, true); + this->HexDump::printDumpAt(dest, true); } void TraceDump::hexAsciiSlot() @@ -1298,8 +1343,9 @@ void TraceDump::selectionUpdatedSlot() QString selEnd = ToPtrString(rvaToVa(getSelectionEnd())); QString info = tr("Dump"); char mod[MAX_MODULE_SIZE] = ""; - if(DbgFunctions()->ModNameFromAddr(rvaToVa(getSelectionStart()), mod, true)) - info = QString(mod) + ""; + //TODO + //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()); } diff --git a/src/gui/Src/Tracer/TraceDump.h b/src/gui/Src/Tracer/TraceDump.h index 18bceb00ac..ca486c1e30 100644 --- a/src/gui/Src/Tracer/TraceDump.h +++ b/src/gui/Src/Tracer/TraceDump.h @@ -21,6 +21,7 @@ class TraceDump : public HexDump void contextMenuEvent(QContextMenuEvent* event); void mouseDoubleClickEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event); + void printDumpAt(dsint parVA, bool select, bool repaint, bool updateTableOffset); signals: void displayReferencesWidget(); @@ -28,7 +29,7 @@ class TraceDump : public HexDump public slots: void gotoExpressionSlot(); - void gotoFileOffsetSlot(); + //void gotoFileOffsetSlot(); void gotoStartSlot(); void gotoEndSlot(); //void gotoPreviousReferenceSlot(); diff --git a/src/gui/Src/Tracer/TraceFileDump.cpp b/src/gui/Src/Tracer/TraceFileDump.cpp index 3d96dce55b..9fdcae35f7 100644 --- a/src/gui/Src/Tracer/TraceFileDump.cpp +++ b/src/gui/Src/Tracer/TraceFileDump.cpp @@ -153,7 +153,7 @@ void TraceFileDump::findMemAreas() } // TraceFileDumpMemoryPage -TraceFileDumpMemoryPage::TraceFileDumpMemoryPage(QObject* parent) : MemoryPage(0, 0, parent) +TraceFileDumpMemoryPage::TraceFileDumpMemoryPage(QObject* parent) : MemoryPage(0x1000, ((duint) - 1) >> 1, parent) { QMutexLocker locker(&lock); dump = nullptr; diff --git a/src/gui/Src/Utils/Configuration.cpp b/src/gui/Src/Utils/Configuration.cpp index aab43963c9..b06506e1ca 100644 --- a/src/gui/Src/Utils/Configuration.cpp +++ b/src/gui/Src/Utils/Configuration.cpp @@ -309,6 +309,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false) insertMenuBuilderBools(&guiBool, "Help", 50); //Main Menu : Help insertMenuBuilderBools(&guiBool, "View", 50); //Main Menu : View insertMenuBuilderBools(&guiBool, "TraceBrowser", 50); //TraceBrowser + insertMenuBuilderBools(&guiBool, "TraceDump", 50); //Trace Dump defaultBools.insert("Gui", guiBool); QMap guiUint; From 42208c0577d96bf924288a4c68244510d4b5dfaa Mon Sep 17 00:00:00 2001 From: Torusrxxx Date: Fri, 1 Sep 2023 04:28:30 +0000 Subject: [PATCH 06/33] Add files via upload --- src/gui/Src/Tracer/TraceDump.cpp | 2894 +++++++++++++------------- src/gui/Src/Tracer/TraceDump.h | 250 +-- src/gui/Src/Tracer/TraceFileDump.cpp | 400 ++-- src/gui/Src/Tracer/TraceFileDump.h | 140 +- 4 files changed, 1842 insertions(+), 1842 deletions(-) diff --git a/src/gui/Src/Tracer/TraceDump.cpp b/src/gui/Src/Tracer/TraceDump.cpp index 3053b8d9af..b63b350534 100644 --- a/src/gui/Src/Tracer/TraceDump.cpp +++ b/src/gui/Src/Tracer/TraceDump.cpp @@ -1,1447 +1,1447 @@ -#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, [this](QMenu*) - { - return mMemoryPage->isAvailable(); - }); - - mCommonActions = new CommonActions(this, getActionHelperFuncs(), [this]() - { - return rvaToVa(getSelectionStart()); - }); - - MenuBuilder* wBinaryMenu = new MenuBuilder(this); - wBinaryMenu->addAction(makeShortcutAction(DIcon("binary_copy"), tr("&Copy"), SLOT(binaryCopySlot()), "ActionBinaryCopy")); - 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); - auto wIsValidReadPtrCallback = [this](QMenu*) - { - duint ptr = 0; - DbgMemRead(rvaToVa(getSelectionStart()), (unsigned char*)&ptr, sizeof(duint)); - return DbgMemIsValidReadPtr(ptr); - }; - - 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")); - - 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(); - }); - 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(); - disconnect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(debugStateChanged(DBGSTATE))); - updateShortcuts(); -} - -void TraceDump::getAttention() -{ - BackgroundFlickerThread* thread = new BackgroundFlickerThread(this, mBackgroundColor, this); - connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); - thread->start(); -} - -void TraceDump::printDumpAt(dsint parVA, bool select, bool repaint, bool updateTableOffset) -{ - // Modified from Hexdump, removed memory page information - // TODO: get memory range from trace instead - duint wSize; - auto wBase = mMemoryPage->getBase(); - dsint wRVA = parVA - wBase; //calculate rva - int wBytePerRowCount = getBytePerRowCount(); //get the number of bytes per row - dsint wRowCount; - - // Byte offset used to be aligned on the given RVA - mByteOffset = (int)((dsint)wRVA % (dsint)wBytePerRowCount); - mByteOffset = mByteOffset > 0 ? wBytePerRowCount - mByteOffset : 0; - - // Compute row count - wRowCount = wSize / wBytePerRowCount; - wRowCount += mByteOffset > 0 ? 1 : 0; - - //if(mRvaDisplayEnabled && mMemPage->getBase() != mRvaDisplayPageBase) - // mRvaDisplayEnabled = false; - - setRowCount(wRowCount); //set the number of rows - - //mMemPage->setAttributes(wBase, wSize); // Set base and size (Useful when memory page changed) - - if(updateTableOffset) - { - setTableOffset(-1); //make sure the requested address is always first - setTableOffset((wRVA + mByteOffset) / wBytePerRowCount); //change the displayed offset - } - - if(select) - { - setSingleSelection(wRVA); - dsint wEndingAddress = wRVA + getSizeOf(mDescriptor.at(0).data.itemSize) - 1; - expandSelectionUpTo(wEndingAddress); - } - - if(repaint) - reloadData(); -} - -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] = ""; - //TODO - //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) - HexDump::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 || !mMemoryPage->isAvailable()) - 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; - } -} - -#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::gotoExpressionSlot() -{ - if(!mMemoryPage->isAvailable()) - return; - if(!mGoto) - mGoto = new GotoDialog(this, false, true, true); - 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()); - GuiAddLogMessage(ToPtrString(value).toUtf8()); - this->HexDump::printDumpAt(value, true); - } -} - -// TODO: Module information need to be read from trace file -/*void TraceDump::gotoFileOffsetSlot() -{ - if(!mMemoryPage->isAvailable()) - 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); - this->printDumpAt(value, true); -}*/ - -void TraceDump::gotoStartSlot() -{ - duint dest = mMemPage->getBase(); - this->HexDump::printDumpAt(dest, true); -} - -void TraceDump::gotoEndSlot() -{ - duint dest = mMemPage->getBase() + mMemPage->getSize() - (getViewableRowsCount() * getBytePerRowCount()); - this->HexDump::printDumpAt(dest, true); -} - -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::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::selectionUpdatedSlot() -{ - QString selStart = ToPtrString(rvaToVa(getSelectionStart())); - QString selEnd = ToPtrString(rvaToVa(getSelectionEnd())); - QString info = tr("Dump"); - char mod[MAX_MODULE_SIZE] = ""; - //TODO - //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(!mMemoryPage->isAvailable()) - 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::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(); -} +#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, [this](QMenu*) + { + return mMemoryPage->isAvailable(); + }); + + mCommonActions = new CommonActions(this, getActionHelperFuncs(), [this]() + { + return rvaToVa(getSelectionStart()); + }); + + MenuBuilder* wBinaryMenu = new MenuBuilder(this); + wBinaryMenu->addAction(makeShortcutAction(DIcon("binary_copy"), tr("&Copy"), SLOT(binaryCopySlot()), "ActionBinaryCopy")); + 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); + auto wIsValidReadPtrCallback = [this](QMenu*) + { + duint ptr = 0; + DbgMemRead(rvaToVa(getSelectionStart()), (unsigned char*)&ptr, sizeof(duint)); + return DbgMemIsValidReadPtr(ptr); + }; + + 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")); + + 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(); + }); + 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(); + disconnect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(debugStateChanged(DBGSTATE))); + updateShortcuts(); +} + +void TraceDump::getAttention() +{ + BackgroundFlickerThread* thread = new BackgroundFlickerThread(this, mBackgroundColor, this); + connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater())); + thread->start(); +} + +void TraceDump::printDumpAt(dsint parVA, bool select, bool repaint, bool updateTableOffset) +{ + // Modified from Hexdump, removed memory page information + // TODO: get memory range from trace instead + duint wSize; + auto wBase = mMemoryPage->getBase(); + dsint wRVA = parVA - wBase; //calculate rva + int wBytePerRowCount = getBytePerRowCount(); //get the number of bytes per row + dsint wRowCount; + + // Byte offset used to be aligned on the given RVA + mByteOffset = (int)((dsint)wRVA % (dsint)wBytePerRowCount); + mByteOffset = mByteOffset > 0 ? wBytePerRowCount - mByteOffset : 0; + + // Compute row count + wRowCount = wSize / wBytePerRowCount; + wRowCount += mByteOffset > 0 ? 1 : 0; + + //if(mRvaDisplayEnabled && mMemPage->getBase() != mRvaDisplayPageBase) + // mRvaDisplayEnabled = false; + + setRowCount(wRowCount); //set the number of rows + + //mMemPage->setAttributes(wBase, wSize); // Set base and size (Useful when memory page changed) + + if(updateTableOffset) + { + setTableOffset(-1); //make sure the requested address is always first + setTableOffset((wRVA + mByteOffset) / wBytePerRowCount); //change the displayed offset + } + + if(select) + { + setSingleSelection(wRVA); + dsint wEndingAddress = wRVA + getSizeOf(mDescriptor.at(0).data.itemSize) - 1; + expandSelectionUpTo(wEndingAddress); + } + + if(repaint) + reloadData(); +} + +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] = ""; + //TODO + //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) + HexDump::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 || !mMemoryPage->isAvailable()) + 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; + } +} + +#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::gotoExpressionSlot() +{ + if(!mMemoryPage->isAvailable()) + return; + if(!mGoto) + mGoto = new GotoDialog(this, false, true, true); + 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()); + GuiAddLogMessage(ToPtrString(value).toUtf8()); + this->HexDump::printDumpAt(value, true); + } +} + +// TODO: Module information need to be read from trace file +/*void TraceDump::gotoFileOffsetSlot() +{ + if(!mMemoryPage->isAvailable()) + 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); + this->printDumpAt(value, true); +}*/ + +void TraceDump::gotoStartSlot() +{ + duint dest = mMemPage->getBase(); + this->HexDump::printDumpAt(dest, true); +} + +void TraceDump::gotoEndSlot() +{ + duint dest = mMemPage->getBase() + mMemPage->getSize() - (getViewableRowsCount() * getBytePerRowCount()); + this->HexDump::printDumpAt(dest, true); +} + +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::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::selectionUpdatedSlot() +{ + QString selStart = ToPtrString(rvaToVa(getSelectionStart())); + QString selEnd = ToPtrString(rvaToVa(getSelectionEnd())); + QString info = tr("Dump"); + char mod[MAX_MODULE_SIZE] = ""; + //TODO + //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(!mMemoryPage->isAvailable()) + 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::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 index ca486c1e30..cde671b8f0 100644 --- a/src/gui/Src/Tracer/TraceDump.h +++ b/src/gui/Src/Tracer/TraceDump.h @@ -1,125 +1,125 @@ -#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); - void printDumpAt(dsint parVA, bool select, bool repaint, bool updateTableOffset); - -signals: - void displayReferencesWidget(); - void showDisassemblyTab(duint selectionStart, duint selectionEnd, duint firstAddress); - -public slots: - 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 binaryCopySlot(); - void binarySaveToFileSlot(); - void findPattern(); - void copyFileOffsetSlot(); - void findReferencesSlot(); - - void selectionUpdatedSlot(); - void syncWithExpressionSlot(); - - 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); -}; +#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); + void printDumpAt(dsint parVA, bool select, bool repaint, bool updateTableOffset); + +signals: + void displayReferencesWidget(); + void showDisassemblyTab(duint selectionStart, duint selectionEnd, duint firstAddress); + +public slots: + 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 binaryCopySlot(); + void binarySaveToFileSlot(); + void findPattern(); + void copyFileOffsetSlot(); + void findReferencesSlot(); + + void selectionUpdatedSlot(); + void syncWithExpressionSlot(); + + 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 9fdcae35f7..d4654942c9 100644 --- a/src/gui/Src/Tracer/TraceFileDump.cpp +++ b/src/gui/Src/Tracer/TraceFileDump.cpp @@ -1,200 +1,200 @@ -#include -#include "TraceFileDump.h" -#include "StringUtil.h" - -TraceFileDump::TraceFileDump() -{ - maxIndex = 0ull; -} - -TraceFileDump::~TraceFileDump() -{ - -} - -void TraceFileDump::clear() -{ - maxIndex = 0ull; - dump.clear(); -} - -unsigned char TraceFileDump::getByte(Key location, bool & success) const -{ - auto it = dump.lower_bound(location); - if(it != dump.end()) - { - if(it->first.addr == location.addr) - { - goto found; - } - else if(it != dump.begin()) - { - // try to get to next record which may hold the required data - --it; - if(it->first.addr == location.addr) - { - goto found; - } - } - } - success = false; - return 0; -found: - success = true; - if(location.index > it->first.index) - { - return it->second.newData; - } - else - { - return it->second.oldData; - } -} - -std::vector TraceFileDump::getBytes(duint addr, duint size, unsigned long long index) const -{ - std::vector buffer; - buffer.resize(size); - for(duint i = 0; i < size; i++) - { - bool success; - buffer[i] = getByte({addr + i, index}, success); - } - return buffer; -} - -// find references to the memory address -std::vector TraceFileDump::getReferences(duint startAddr, duint endAddr) const -{ - std::vector index; - if(endAddr < startAddr) - std::swap(endAddr, startAddr); - // find references to the memory address - auto it = dump.lower_bound({endAddr, maxIndex + 1}); - while(it != dump.end() && it->first.addr >= startAddr && it->first.addr <= endAddr) - { - index.push_back(it->first.index); - ++it; - } - if(index.empty()) - return index; - // rearrange the array and remove duplicates - std::sort(index.begin(), index.end()); - std::vector result; - result.push_back(index[0]); - for(size_t i = 1; i < index.size(); i++) - { - if(index[i] != result[result.size() - 1]) - result.push_back(index[i]); - } - return result; -} - -//void TraceFileDump::addMemAccess(duint addr, DumpRecord record) -//{ -// Key location = {addr, maxIndex}; -// dump.insert(std::make_pair(location, record)); -//} - -void TraceFileDump::addMemAccess(duint addr, const void* oldData, const void* newData, size_t size) -{ - std::vector> records; - records.resize(size); - // insert in the correct order - for(size_t i = size; i > 0; i--) - { - auto b = size - i; - records[i - 1].first.addr = addr + b; - records[i - 1].first.index = maxIndex; - records[i - 1].second.oldData = ((const unsigned char*)oldData)[b]; - records[i - 1].second.newData = ((const unsigned char*)newData)[b]; - records[i - 1].second.isWrite = 0; //TODO - records[i - 1].second.isExecute = 0; - } - dump.insert(records.begin(), records.end()); -} - -// Find continuous memory areas. It is done separate from adding memory accesses because the number of addresses is less than that of memory accesses -// TODO: We also need another findMemAreas() which only updates incrementally, when the user steps while tracing -void TraceFileDump::findMemAreas() -{ - memAreas.clear(); - if(dump.empty()) - return; - duint addr = dump.begin()->first.addr; //highest address - duint end = addr; - duint start; - // find first access to addr - do - { - auto it = dump.lower_bound({addr - 1, maxIndex + 1}); - // try to find out if addr-1 is in the dump - for(; it != dump.end(); it = dump.lower_bound({addr - 1, maxIndex + 1})) - { - if(it->first.addr != addr - 1) - break; - addr--; - } - // addr-1 is not in the dump, insert the memory area - start = addr; - memAreas.push_back(std::make_pair(start, end)); - // get to next lowest address - if(it != dump.end()) - { - addr = it->first.addr; - end = addr; - } - else - { - break; - } - } - while(true); -} - -// TraceFileDumpMemoryPage -TraceFileDumpMemoryPage::TraceFileDumpMemoryPage(QObject* parent) : MemoryPage(0x1000, ((duint) - 1) >> 1, parent) -{ - QMutexLocker locker(&lock); - dump = nullptr; -} - -void TraceFileDumpMemoryPage::setSelectedIndex(unsigned long long index) -{ - QMutexLocker locker(&lock); - if(dump) - selectedIndex = std::min(index, dump->getMaxIndex()); - else - selectedIndex = 0ull; -} - -void TraceFileDumpMemoryPage::setDumpObject(TraceFileDump* dump) -{ - QMutexLocker locker(&lock); - this->dump = dump; -} - -bool TraceFileDumpMemoryPage::isAvailable() const -{ - return !!this->dump; -} - -unsigned long long TraceFileDumpMemoryPage::getSelectedIndex() const -{ - return selectedIndex; -} - -bool TraceFileDumpMemoryPage::read(void* parDest, dsint parRVA, duint parSize) const -{ - QMutexLocker locker(&lock); - 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 -} +#include +#include "TraceFileDump.h" +#include "StringUtil.h" + +TraceFileDump::TraceFileDump() +{ + maxIndex = 0ull; +} + +TraceFileDump::~TraceFileDump() +{ + +} + +void TraceFileDump::clear() +{ + maxIndex = 0ull; + dump.clear(); +} + +unsigned char TraceFileDump::getByte(Key location, bool & success) const +{ + auto it = dump.lower_bound(location); + if(it != dump.end()) + { + if(it->first.addr == location.addr) + { + goto found; + } + else if(it != dump.begin()) + { + // try to get to next record which may hold the required data + --it; + if(it->first.addr == location.addr) + { + goto found; + } + } + } + success = false; + return 0; +found: + success = true; + if(location.index > it->first.index) + { + return it->second.newData; + } + else + { + return it->second.oldData; + } +} + +std::vector TraceFileDump::getBytes(duint addr, duint size, unsigned long long index) const +{ + std::vector buffer; + buffer.resize(size); + for(duint i = 0; i < size; i++) + { + bool success; + buffer[i] = getByte({addr + i, index}, success); + } + return buffer; +} + +// find references to the memory address +std::vector TraceFileDump::getReferences(duint startAddr, duint endAddr) const +{ + std::vector index; + if(endAddr < startAddr) + std::swap(endAddr, startAddr); + // find references to the memory address + auto it = dump.lower_bound({endAddr, maxIndex + 1}); + while(it != dump.end() && it->first.addr >= startAddr && it->first.addr <= endAddr) + { + index.push_back(it->first.index); + ++it; + } + if(index.empty()) + return index; + // rearrange the array and remove duplicates + std::sort(index.begin(), index.end()); + std::vector result; + result.push_back(index[0]); + for(size_t i = 1; i < index.size(); i++) + { + if(index[i] != result[result.size() - 1]) + result.push_back(index[i]); + } + return result; +} + +//void TraceFileDump::addMemAccess(duint addr, DumpRecord record) +//{ +// Key location = {addr, maxIndex}; +// dump.insert(std::make_pair(location, record)); +//} + +void TraceFileDump::addMemAccess(duint addr, const void* oldData, const void* newData, size_t size) +{ + std::vector> records; + records.resize(size); + // insert in the correct order + for(size_t i = size; i > 0; i--) + { + auto b = size - i; + records[i - 1].first.addr = addr + b; + records[i - 1].first.index = maxIndex; + records[i - 1].second.oldData = ((const unsigned char*)oldData)[b]; + records[i - 1].second.newData = ((const unsigned char*)newData)[b]; + records[i - 1].second.isWrite = 0; //TODO + records[i - 1].second.isExecute = 0; + } + dump.insert(records.begin(), records.end()); +} + +// Find continuous memory areas. It is done separate from adding memory accesses because the number of addresses is less than that of memory accesses +// TODO: We also need another findMemAreas() which only updates incrementally, when the user steps while tracing +void TraceFileDump::findMemAreas() +{ + memAreas.clear(); + if(dump.empty()) + return; + duint addr = dump.begin()->first.addr; //highest address + duint end = addr; + duint start; + // find first access to addr + do + { + auto it = dump.lower_bound({addr - 1, maxIndex + 1}); + // try to find out if addr-1 is in the dump + for(; it != dump.end(); it = dump.lower_bound({addr - 1, maxIndex + 1})) + { + if(it->first.addr != addr - 1) + break; + addr--; + } + // addr-1 is not in the dump, insert the memory area + start = addr; + memAreas.push_back(std::make_pair(start, end)); + // get to next lowest address + if(it != dump.end()) + { + addr = it->first.addr; + end = addr; + } + else + { + break; + } + } + while(true); +} + +// TraceFileDumpMemoryPage +TraceFileDumpMemoryPage::TraceFileDumpMemoryPage(QObject* parent) : MemoryPage(0x1000, ((duint) - 1) >> 1, parent) +{ + QMutexLocker locker(&lock); + dump = nullptr; +} + +void TraceFileDumpMemoryPage::setSelectedIndex(unsigned long long index) +{ + QMutexLocker locker(&lock); + if(dump) + selectedIndex = std::min(index, dump->getMaxIndex()); + else + selectedIndex = 0ull; +} + +void TraceFileDumpMemoryPage::setDumpObject(TraceFileDump* dump) +{ + QMutexLocker locker(&lock); + this->dump = dump; +} + +bool TraceFileDumpMemoryPage::isAvailable() const +{ + return !!this->dump; +} + +unsigned long long TraceFileDumpMemoryPage::getSelectedIndex() const +{ + return selectedIndex; +} + +bool TraceFileDumpMemoryPage::read(void* parDest, dsint parRVA, duint parSize) const +{ + QMutexLocker locker(&lock); + 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 c963ff3aab..f0f081ff02 100644 --- a/src/gui/Src/Tracer/TraceFileDump.h +++ b/src/gui/Src/Tracer/TraceFileDump.h @@ -1,70 +1,70 @@ -#pragma once - -#include "Imports.h" -#include -#include -#include "MemoryPage.h" - -class TraceFileDump -{ -public: - struct Key - { - duint addr; - unsigned long long index; - friend bool operator <(const Key & a, const Key & b) - { - // order is inverted, highest address is less! We want to use lower_bound() to find last memory access index. - return a.addr > b.addr || a.addr == b.addr && a.index > b.index; - } - }; - struct DumpRecord - { - unsigned char oldData; - unsigned char newData; - unsigned char isWrite; - unsigned char isExecute; - }; - - TraceFileDump(); - ~TraceFileDump(); - void clear(); - // Read a byte at "addr" at the moment given in "index" - unsigned char getByte(Key location, bool & success) const; - std::vector getBytes(duint addr, duint size, unsigned long long index) const; - std::vector getReferences(duint startAddr, duint endAddr) const; - // Insert a memory access record - //void addMemAccess(duint addr, DumpRecord record); - void addMemAccess(duint addr, const void* oldData, const void* newData, size_t size); - inline void increaseIndex() - { - maxIndex++; - } - inline unsigned long long getMaxIndex() - { - return maxIndex; - } - // Find continuous memory areas - void findMemAreas(); - std::vector> memAreas; -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); - bool isAvailable() const; -private: - TraceFileDump* dump; - mutable QMutex lock; - unsigned long long selectedIndex = 0ull; -}; +#pragma once + +#include "Imports.h" +#include +#include +#include "MemoryPage.h" + +class TraceFileDump +{ +public: + struct Key + { + duint addr; + unsigned long long index; + friend bool operator <(const Key & a, const Key & b) + { + // order is inverted, highest address is less! We want to use lower_bound() to find last memory access index. + return a.addr > b.addr || a.addr == b.addr && a.index > b.index; + } + }; + struct DumpRecord + { + unsigned char oldData; + unsigned char newData; + unsigned char isWrite; + unsigned char isExecute; + }; + + TraceFileDump(); + ~TraceFileDump(); + void clear(); + // Read a byte at "addr" at the moment given in "index" + unsigned char getByte(Key location, bool & success) const; + std::vector getBytes(duint addr, duint size, unsigned long long index) const; + std::vector getReferences(duint startAddr, duint endAddr) const; + // Insert a memory access record + //void addMemAccess(duint addr, DumpRecord record); + void addMemAccess(duint addr, const void* oldData, const void* newData, size_t size); + inline void increaseIndex() + { + maxIndex++; + } + inline unsigned long long getMaxIndex() + { + return maxIndex; + } + // Find continuous memory areas + void findMemAreas(); + std::vector> memAreas; +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); + bool isAvailable() const; +private: + TraceFileDump* dump; + mutable QMutex lock; + unsigned long long selectedIndex = 0ull; +}; From 9750488bb23ac2aaa43212060eb2eedfc22a61d6 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Fri, 15 Sep 2023 12:00:33 +0800 Subject: [PATCH 07/33] Fixed empty dump --- src/gui/Src/Tracer/TraceDump.cpp | 33 +++++++++++++++++++------- src/gui/Src/Tracer/TraceDump.h | 1 + src/gui/Src/Tracer/TraceFileDump.cpp | 2 +- src/gui/Src/Tracer/TraceFileReader.cpp | 13 ++++++---- src/gui/Src/Tracer/TraceWidget.cpp | 10 +++++--- 5 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/gui/Src/Tracer/TraceDump.cpp b/src/gui/Src/Tracer/TraceDump.cpp index b63b350534..dae0b6cdc3 100644 --- a/src/gui/Src/Tracer/TraceDump.cpp +++ b/src/gui/Src/Tracer/TraceDump.cpp @@ -239,6 +239,19 @@ void TraceDump::setupContextMenu() updateShortcuts(); } +void TraceDump::mousePressEvent(QMouseEvent* event) +{ + if(event->buttons() == Qt::MiddleButton) //copy address to clipboard + { + //Allow copying while not debugging + MessageBeep(MB_OK); + QString addrText = ToPtrString(rvaToVa(getInitialSelection())); + Bridge::CopyToClipboard(addrText); + return; + } + HexDump::mousePressEvent(event); +} + void TraceDump::getAttention() { BackgroundFlickerThread* thread = new BackgroundFlickerThread(this, mBackgroundColor, this); @@ -250,9 +263,15 @@ void TraceDump::printDumpAt(dsint parVA, bool select, bool repaint, bool updateT { // Modified from Hexdump, removed memory page information // TODO: get memory range from trace instead - duint wSize; + const duint wSize = 0x1000; // TODO: Using 4KB pages currently auto wBase = mMemoryPage->getBase(); dsint wRVA = parVA - wBase; //calculate rva + if(wRVA < 0 || wRVA >= wSize) + { + wBase = parVA & ~(wSize - 1); + mMemoryPage->setAttributes(wBase, wSize); + wRVA = parVA - wBase; //calculate rva + } int wBytePerRowCount = getBytePerRowCount(); //get the number of bytes per row dsint wRowCount; @@ -269,8 +288,6 @@ void TraceDump::printDumpAt(dsint parVA, bool select, bool repaint, bool updateT setRowCount(wRowCount); //set the number of rows - //mMemPage->setAttributes(wBase, wSize); // Set base and size (Useful when memory page changed) - if(updateTableOffset) { setTableOffset(-1); //make sure the requested address is always first @@ -337,8 +354,8 @@ void TraceDump::getColumnRichText(int col, dsint rva, RichTextPainter::List & ri 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) - HexDump::printDumpAt(mMemPage->getBase(), false, false); + //if(rowBase == 0 && mByteOffset != 0) + // HexDump::printDumpAt(mMemPage->getBase(), false, false); if(!col) //address { @@ -527,7 +544,7 @@ void TraceDump::gotoExpressionSlot() { duint value = DbgValFromString(mGoto->expressionText.toUtf8().constData()); GuiAddLogMessage(ToPtrString(value).toUtf8()); - this->HexDump::printDumpAt(value, true); + this->printDumpAt(value, true, true, true); } } @@ -561,13 +578,13 @@ void TraceDump::gotoExpressionSlot() void TraceDump::gotoStartSlot() { duint dest = mMemPage->getBase(); - this->HexDump::printDumpAt(dest, true); + this->printDumpAt(dest, true, true, true); } void TraceDump::gotoEndSlot() { duint dest = mMemPage->getBase() + mMemPage->getSize() - (getViewableRowsCount() * getBytePerRowCount()); - this->HexDump::printDumpAt(dest, true); + this->printDumpAt(dest, true, true, true); } void TraceDump::hexAsciiSlot() diff --git a/src/gui/Src/Tracer/TraceDump.h b/src/gui/Src/Tracer/TraceDump.h index cde671b8f0..9a89f802ab 100644 --- a/src/gui/Src/Tracer/TraceDump.h +++ b/src/gui/Src/Tracer/TraceDump.h @@ -21,6 +21,7 @@ class TraceDump : public HexDump void contextMenuEvent(QContextMenuEvent* event); void mouseDoubleClickEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event); + void mousePressEvent(QMouseEvent* event); void printDumpAt(dsint parVA, bool select, bool repaint, bool updateTableOffset); signals: diff --git a/src/gui/Src/Tracer/TraceFileDump.cpp b/src/gui/Src/Tracer/TraceFileDump.cpp index d4654942c9..820cf938dd 100644 --- a/src/gui/Src/Tracer/TraceFileDump.cpp +++ b/src/gui/Src/Tracer/TraceFileDump.cpp @@ -153,7 +153,7 @@ void TraceFileDump::findMemAreas() } // TraceFileDumpMemoryPage -TraceFileDumpMemoryPage::TraceFileDumpMemoryPage(QObject* parent) : MemoryPage(0x1000, ((duint) - 1) >> 1, parent) +TraceFileDumpMemoryPage::TraceFileDumpMemoryPage(QObject* parent) : MemoryPage(0x10000, 0x1000, parent) { QMutexLocker locker(&lock); dump = nullptr; diff --git a/src/gui/Src/Tracer/TraceFileReader.cpp b/src/gui/Src/Tracer/TraceFileReader.cpp index 0dd018bfd5..ae2492be9b 100644 --- a/src/gui/Src/Tracer/TraceFileReader.cpp +++ b/src/gui/Src/Tracer/TraceFileReader.cpp @@ -577,17 +577,19 @@ void TraceFileReader::purgeLastPage() } } +// Extract memory access information of given index into dump object void TraceFileReader::buildDump(unsigned long long index) { - int MemoryOperandsCount = MemoryAccessCount(index); - if(MemoryOperandsCount == 0) //LEA and NOP instructions - return; Zydis zydis; unsigned char opcode[MAX_DISASM_BUFFER]; int opcodeSize; REGDUMP registers = Registers(index);; OpCode(index, opcode, &opcodeSize); + // Always add opcode into dump dump.addMemAccess(registers.regcontext.cip, opcode, opcode, opcodeSize); + int MemoryOperandsCount = MemoryAccessCount(index); + if(MemoryOperandsCount == 0) //LEA and NOP instructions are ignored here + return; zydis.Disassemble(registers.regcontext.cip, opcode, opcodeSize); duint oldMemory[32]; duint newMemory[32]; @@ -623,9 +625,10 @@ void TraceFileReader::buildDump(unsigned long long index) } } +// Build dump index to the given index void TraceFileReader::buildDumpTo(unsigned long long index) { - auto start = dump.getMaxIndex(); + auto start = dump.getMaxIndex(); // Don't re-add existing dump for(auto i = start + 1; i < index; i++) { dump.increaseIndex(); @@ -633,7 +636,7 @@ void TraceFileReader::buildDumpTo(unsigned long long index) } } -void TraceFileReader::debugdump(unsigned long long index) +void TraceFileReader::debugdump(unsigned long long index) //TODO: remove me { dump.findMemAreas(); for(auto c : dump.memAreas) diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index d02ab37aba..1ef2674f9f 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -58,14 +58,14 @@ TraceWidget::TraceWidget(QWidget* parent) : //overview ui->mBotRightFrameLayout->addWidget(mOverview); - //set up overview + // TODO: set up overview mOverview->addColumnAt(0, "", true); mOverview->setShowHeader(false); mOverview->setRowCount(4); mOverview->setCellContent(0, 0, "hello"); mOverview->setCellContent(1, 0, "world"); mOverview->setCellContent(2, 0, "00000000"); - mOverview->setCellContent(3, 0, "here we will list all control flow transfers"); + mOverview->setCellContent(3, 0, "TODO: Draw call stack here"); //mOverview->hide(); ui->mTopHSplitter->setSizes(QList({1000, 1})); ui->mTopLeftVSplitter->setSizes(QList({1000, 1})); @@ -85,10 +85,14 @@ void TraceWidget::traceSelectionChanged(unsigned long long selection) { if(selection < traceFile->Length()) { + // update registers view registers = traceFile->Registers(selection); mInfo->update(selection, traceFile, registers); - traceFile->buildDumpTo(selection); + // update dump view + traceFile->buildDumpTo(selection); // TODO: sometimes this can be slow mMemoryPage->setDumpObject(traceFile->getDump()); + mMemoryPage->setSelectedIndex(selection); + mDump->reloadData(); } else memset(®isters, 0, sizeof(registers)); From b45acd5d56f127e830dfc9bec87321803d7d5018 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Fri, 15 Sep 2023 17:44:25 +0800 Subject: [PATCH 08/33] fix PUSH memory access don't appear in dump --- src/gui/Src/Tracer/TraceFileReader.cpp | 78 +++++++++++++++++--- src/gui/Src/Tracer/TraceFileReaderInternal.h | 4 +- 2 files changed, 69 insertions(+), 13 deletions(-) diff --git a/src/gui/Src/Tracer/TraceFileReader.cpp b/src/gui/Src/Tracer/TraceFileReader.cpp index ae2492be9b..0efcc0a2c7 100644 --- a/src/gui/Src/Tracer/TraceFileReader.cpp +++ b/src/gui/Src/Tracer/TraceFileReader.cpp @@ -580,7 +580,6 @@ void TraceFileReader::purgeLastPage() // Extract memory access information of given index into dump object void TraceFileReader::buildDump(unsigned long long index) { - Zydis zydis; unsigned char opcode[MAX_DISASM_BUFFER]; int opcodeSize; REGDUMP registers = Registers(index);; @@ -590,24 +589,34 @@ void TraceFileReader::buildDump(unsigned long long index) int MemoryOperandsCount = MemoryAccessCount(index); if(MemoryOperandsCount == 0) //LEA and NOP instructions are ignored here return; - zydis.Disassemble(registers.regcontext.cip, opcode, opcodeSize); + // TODO: This doesn't get correct memory operand size duint oldMemory[32]; duint newMemory[32]; duint address[32]; bool isValid[32]; - bool used[32]; MemoryAccessInfo(index, address, oldMemory, newMemory, isValid); - memset(used, 0, sizeof(used)); - for(int opindex = 0; opindex < zydis.OpCount(); opindex++) + for(int i = 0; i < MemoryOperandsCount; i++) { - size_t value = zydis.ResolveOpValue(opindex, [®isters](ZydisRegister reg) - { - return resolveZydisRegister(registers, reg); - }); - if(zydis[opindex].type == ZYDIS_OPERAND_TYPE_MEMORY) + dump.addMemAccess(address[i], &oldMemory[i], &newMemory[i], sizeof(duint)); + } + /* + // TODO: This works poorly for edge cases, still doesn't work with PUSH DWORD PTR FS:[ESP+EAX] + Zydis zydis; + zydis.Disassemble(registers.regcontext.cip, opcode, opcodeSize); + //bool used[32]; + //memset(used, 0, sizeof(used)); + // fix PUSH DWORD PTR [ESP] uses different ESP values + if(zydis.GetInstr()->mnemonic == ZYDIS_MNEMONIC_PUSH) // fix PUSH instructions, add explicit memory operand + { + const auto & operand = zydis[0]; + if(operand.type == ZYDIS_OPERAND_TYPE_MEMORY) { int size; - size = ceil(zydis[opindex].size / 8.0); + size = ceil((float)operand.size / 8.0f); + size_t value = zydis.ResolveOpValue(0, [®isters](ZydisRegister reg) + { + return resolveZydisRegister(registers, reg); + }); bool found = false; for(int i = 0; i < MemoryOperandsCount; i++) { @@ -623,6 +632,53 @@ void TraceFileReader::buildDump(unsigned long long index) //GuiAddLogMessage(QString("buildDump bug %1???\n").arg(index).toUtf8().constData()); } } + // fix PUSH instructions, add implicit memory operand + if(zydis.GetInstr()->mnemonic == ZYDIS_MNEMONIC_PUSH ||zydis.GetInstr()->mnemonic == ZYDIS_MNEMONIC_PUSHF || zydis.GetInstr()->mnemonic == ZYDIS_MNEMONIC_PUSHFD || zydis.GetInstr()->mnemonic == ZYDIS_MNEMONIC_PUSHFQ) + { + size_t new_csp = registers.regcontext.csp - sizeof(duint); + bool found = false; + for(int i = 0; i < MemoryOperandsCount; i++) + { + if(address[i] != new_csp) + continue; + dump.addMemAccess(address[i], &oldMemory[i], &newMemory[i], sizeof(duint)); + found = true; + break; + } + //if(!found) + //bug??? + //GuiAddLogMessage(QString("buildDump bug %1???\n").arg(index).toUtf8().constData()); + } + else + { + for(int opindex = 0; opindex < zydis.GetInstr()->operandCount; opindex++) + { + const auto & operand = zydis.GetInstr()->operands[opindex]; + if(operand.type == ZYDIS_OPERAND_TYPE_MEMORY) + { + int size; + size = ceil((float)operand.size / 8.0f); + size_t value = zydis.ResolveOpValue(opindex, [®isters](ZydisRegister reg) + { + return resolveZydisRegister(registers, reg); + }); + bool found = false; + for(int i = 0; i < MemoryOperandsCount; i++) + { + // TODO: fix up FS/GS segment + if(address[i] != value) + continue; + dump.addMemAccess(address[i], &oldMemory[i], &newMemory[i], size); + found = true; + break; + } + //if(!found) + //bug??? + //GuiAddLogMessage(QString("buildDump bug %1???\n").arg(index).toUtf8().constData()); + } + } + } + */ } // Build dump index to the given index diff --git a/src/gui/Src/Tracer/TraceFileReaderInternal.h b/src/gui/Src/Tracer/TraceFileReaderInternal.h index 85ac5edb55..17391d8f33 100644 --- a/src/gui/Src/Tracer/TraceFileReaderInternal.h +++ b/src/gui/Src/Tracer/TraceFileReaderInternal.h @@ -34,10 +34,10 @@ class TraceFilePage TraceFileReader* mParent; std::vector mRegisters; QByteArray opcodes; - std::vector opcodeOffset; + std::vector opcodeOffset; std::vector opcodeSize; std::vector instructions; - std::vector memoryOperandOffset; + std::vector memoryOperandOffset; std::vector memoryFlags; std::vector memoryAddress; std::vector oldMemory; From de2891718970335c26cb81217cb5512cc7927357 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Fri, 15 Sep 2023 21:06:19 +0800 Subject: [PATCH 09/33] optimize getBytes and fixed empty dump while not debugging --- src/gui/Src/Tracer/TraceDump.cpp | 9 +-- src/gui/Src/Tracer/TraceFileDump.cpp | 92 +++++++++++++++++++++++--- src/gui/Src/Tracer/TraceFileReader.cpp | 2 +- 3 files changed, 90 insertions(+), 13 deletions(-) diff --git a/src/gui/Src/Tracer/TraceDump.cpp b/src/gui/Src/Tracer/TraceDump.cpp index dae0b6cdc3..d9707c9579 100644 --- a/src/gui/Src/Tracer/TraceDump.cpp +++ b/src/gui/Src/Tracer/TraceDump.cpp @@ -20,6 +20,7 @@ TraceDump::TraceDump(TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent) : mMemoryPage(memoryPage), HexDump(parent, memoryPage) { mDisas = disas; + setDrawDebugOnly(false); //mMultiDump = multiDump; duint setting; @@ -224,7 +225,7 @@ void TraceDump::setupContextMenu() 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->addAction(makeAction(DIcon("processor-cpu"), tr("&Disassembly"), SLOT(disassemblySlot())))->setEnabled(false); //TODO //mMenuBuilder->addSeparator(); //mMenuBuilder->addBuilder(new MenuBuilder(this, [this](QMenu * menu) @@ -1257,9 +1258,9 @@ void TraceDump::addressUnicodeSlot() void TraceDump::disassemblySlot() { - SELECTIONDATA selection; - selectionGet(&selection); - emit showDisassemblyTab(selection.start, selection.end, rvaToVa(getTableOffsetRva())); + //SELECTIONDATA selection; + //selectionGet(&selection); + //emit showDisassemblyTab(selection.start, selection.end, rvaToVa(getTableOffsetRva())); } void TraceDump::selectionGet(SELECTIONDATA* selection) diff --git a/src/gui/Src/Tracer/TraceFileDump.cpp b/src/gui/Src/Tracer/TraceFileDump.cpp index 820cf938dd..10ff2d340b 100644 --- a/src/gui/Src/Tracer/TraceFileDump.cpp +++ b/src/gui/Src/Tracer/TraceFileDump.cpp @@ -21,11 +21,12 @@ void TraceFileDump::clear() unsigned char TraceFileDump::getByte(Key location, bool & success) const { auto it = dump.lower_bound(location); + success = false; if(it != dump.end()) { if(it->first.addr == location.addr) { - goto found; + success = true; } else if(it != dump.begin()) { @@ -33,14 +34,14 @@ unsigned char TraceFileDump::getByte(Key location, bool & success) const --it; if(it->first.addr == location.addr) { - goto found; + success = true; } } } - success = false; - return 0; -found: - success = true; + if(!success) + { + return 0; + } if(location.index > it->first.index) { return it->second.newData; @@ -54,11 +55,86 @@ unsigned char TraceFileDump::getByte(Key location, bool & success) const std::vector TraceFileDump::getBytes(duint addr, duint size, unsigned long long index) const { std::vector buffer; + char failedTimes = 0; buffer.resize(size); for(duint i = 0; i < size; i++) { - bool success; - buffer[i] = getByte({addr + i, index}, success); + Key location = {addr + i, index}; + auto it = dump.lower_bound(location); + bool success = false; + if(it != dump.end()) + { + if(it->first.addr == location.addr) + { + success = true; + } + else if(it != dump.begin()) + { + // try to get to next record which may hold the required data + --it; + if(it->first.addr == location.addr) + { + success = true; + } + else if(it->first.addr > location.addr) // this must be higher address than requested location, gap should be filled with zeroes + { + duint gap_size = it->first.addr - location.addr; + gap_size = std::min(gap_size, size - i); // prevent overflow + memset(&buffer[i], 0, gap_size); + i += gap_size - 1; + continue; + } + else + { + GuiAddLogMessage("impossible!"); + } + } + } + if(!success) + { + buffer[i] = 0; + continue; + } + if(location.index > it->first.index) + { + buffer[i] = it->second.newData; + } + else + { + buffer[i] = it->second.oldData; // Old data of new instruction is preferred + } + // Peek at next entries to see if we are lucky to have data for addr+i+1 easily, works for data only accessed once + while(it != dump.begin() && i + 1 < size && failedTimes < 5) + { + --it; + if(it->first.addr == addr + i + 1) + { + // At the right address, but still not sure whether the index is right + if(it == dump.begin() || std::prev(it)->first.addr != addr + i + 1) + { + // OK + ++i; + if(location.index > it->first.index) + { + buffer[i] = it->second.newData; + } + else + { + buffer[i] = it->second.oldData; // Old data of new instruction is preferred + } + failedTimes = 0; + continue; + } + } + failedTimes++; // This trick doesn't work for frequently accessed memory areas, e.g call stack. Disable it quickly. + break; + } + if(it == dump.begin() && i < size - 1) + { + // Nothing more, fill the rest with zeros and done + memset(&buffer[i + 1], 0, size - i - 1); + break; + } } return buffer; } diff --git a/src/gui/Src/Tracer/TraceFileReader.cpp b/src/gui/Src/Tracer/TraceFileReader.cpp index 0efcc0a2c7..2c4e2821b7 100644 --- a/src/gui/Src/Tracer/TraceFileReader.cpp +++ b/src/gui/Src/Tracer/TraceFileReader.cpp @@ -685,7 +685,7 @@ void TraceFileReader::buildDump(unsigned long long index) void TraceFileReader::buildDumpTo(unsigned long long index) { auto start = dump.getMaxIndex(); // Don't re-add existing dump - for(auto i = start + 1; i < index; i++) + for(auto i = start + 1; i <= index; i++) { dump.increaseIndex(); buildDump(i); From 090da1a2eeb31ebede2967f4a0fc7bb934bdd64d Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Sat, 16 Sep 2023 10:10:16 +0800 Subject: [PATCH 10/33] Multiple trace tabs --- src/gui/Src/Gui/MainWindow.cpp | 10 +++--- src/gui/Src/Gui/MainWindow.h | 4 +-- src/gui/Src/Tracer/TraceManager.cpp | 50 +++++++++++++++++++++++++++++ src/gui/Src/Tracer/TraceManager.h | 22 +++++++++++++ src/gui/x64dbg.pro | 2 ++ src/x64dbg_translations.pro | 6 ++-- 6 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 src/gui/Src/Tracer/TraceManager.cpp create mode 100644 src/gui/Src/Tracer/TraceManager.h diff --git a/src/gui/Src/Gui/MainWindow.cpp b/src/gui/Src/Gui/MainWindow.cpp index 5aa23305f5..2e454bd8f8 100644 --- a/src/gui/Src/Gui/MainWindow.cpp +++ b/src/gui/Src/Gui/MainWindow.cpp @@ -53,8 +53,8 @@ #include "MRUList.h" #include "AboutDialog.h" #include "UpdateChecker.h" -#include "Tracer/TraceBrowser.h" -#include "Tracer/TraceWidget.h" +#include "Tracer/TraceManager.h" +//#include "Tracer/TraceWidget.h" #include "Utils/MethodInvoker.h" MainWindow::MainWindow(QWidget* parent) @@ -226,11 +226,11 @@ MainWindow::MainWindow(QWidget* parent) mHandlesView->setWindowIcon(DIcon("handles")); // Trace view - mTraceWidget = new TraceWidget(this); + mTraceWidget = new TraceManager(this); mTraceWidget->setWindowTitle(tr("Trace")); mTraceWidget->setWindowIcon(DIcon("trace")); - connect(mTraceWidget->getTraceBrowser(), SIGNAL(displayReferencesWidget()), this, SLOT(displayReferencesWidget())); - connect(mTraceWidget->getTraceBrowser(), SIGNAL(displayLogWidget()), this, SLOT(displayLogWidget())); + //connect(mTraceWidget->getTraceBrowser(), SIGNAL(displayReferencesWidget()), this, SLOT(displayReferencesWidget())); + //connect(mTraceWidget->getTraceBrowser(), SIGNAL(displayLogWidget()), this, SLOT(displayLogWidget())); mTabWidget = new MHTabWidget(this, true, true); diff --git a/src/gui/Src/Gui/MainWindow.h b/src/gui/Src/Gui/MainWindow.h index 043f68513e..8f74a3fd31 100644 --- a/src/gui/Src/Gui/MainWindow.h +++ b/src/gui/Src/Gui/MainWindow.h @@ -33,7 +33,7 @@ class SettingsDialog; class SimpleTraceDialog; class MRUList; class UpdateChecker; -class TraceWidget; +class TraceManager; namespace Ui { @@ -174,7 +174,7 @@ public slots: CalculatorDialog* mCalculatorDialog; HandlesView* mHandlesView; NotesManager* mNotesManager; - TraceWidget* mTraceWidget; + TraceManager* mTraceWidget; SimpleTraceDialog* mSimpleTraceDialog; UpdateChecker* mUpdateChecker; DebugStatusLabel* mStatusLabel; diff --git a/src/gui/Src/Tracer/TraceManager.cpp b/src/gui/Src/Tracer/TraceManager.cpp new file mode 100644 index 0000000000..e93d818b14 --- /dev/null +++ b/src/gui/Src/Tracer/TraceManager.cpp @@ -0,0 +1,50 @@ +#include "TraceManager.h" +#include "MiscUtil.h" + +TraceManager::TraceManager(QWidget* parent) : QTabWidget(parent) +{ + setMovable(true); + setTabsClosable(true); + + //Open + mOpen = new QPushButton(this); + mOpen->setIcon(DIcon("control-record")); //TODO: New icon + mOpen->setToolTip(tr("Open")); + connect(mOpen, SIGNAL(clicked()), this, SLOT(open())); + setCornerWidget(mOpen, Qt::TopRightCorner); + + //Close All Tabs + mCloseAllTabs = new QPushButton(this); + mCloseAllTabs->setIcon(DIcon("close-all-tabs")); + mCloseAllTabs->setToolTip(tr("Close All Tabs")); + connect(mCloseAllTabs, SIGNAL(clicked()), this, SLOT(closeAllTabs())); + setCornerWidget(mCloseAllTabs, Qt::TopLeftCorner); + + connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int))); + + open(); +} + +void TraceManager::open() +{ + //load the new file + TraceWidget* newView = new TraceWidget(this); + addTab(newView, tr("Trace")); //TODO: Proper title + setCurrentIndex(count() - 1); +} + +void TraceManager::closeTab(int index) +{ + auto view = qobject_cast(widget(index)); + removeTab(index); + if(view) + delete view; +} + +void TraceManager::closeAllTabs() +{ + while(count()) + { + closeTab(0); + } +} diff --git a/src/gui/Src/Tracer/TraceManager.h b/src/gui/Src/Tracer/TraceManager.h new file mode 100644 index 0000000000..4e70915895 --- /dev/null +++ b/src/gui/Src/Tracer/TraceManager.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include +#include "TraceWidget.h" + +class TraceManager : public QTabWidget +{ + Q_OBJECT +public: + explicit TraceManager(QWidget* parent = 0); + +public slots: + void open(); + void closeTab(int index); + void closeAllTabs(); + +private: + QPushButton* mOpen; + QPushButton* mCloseAllTabs; +}; diff --git a/src/gui/x64dbg.pro b/src/gui/x64dbg.pro index 0665df4b42..ce1a733b6d 100644 --- a/src/gui/x64dbg.pro +++ b/src/gui/x64dbg.pro @@ -83,6 +83,7 @@ SOURCES += \ Src/Tracer/TraceDump.cpp \ Src/Tracer/TraceFileDump.cpp \ Src/Tracer/TraceInfoBox.cpp \ + Src/Tracer/TraceManager.cpp \ Src/Tracer/TraceRegisters.cpp \ Src/Tracer/TraceWidget.cpp \ Src/Utils/CommonActions.cpp \ @@ -207,6 +208,7 @@ HEADERS += \ Src/Tracer/TraceDump.h \ Src/Tracer/TraceFileDump.h \ Src/Tracer/TraceInfoBox.h \ + Src/Tracer/TraceManager.h \ Src/Tracer/TraceRegisters.h \ Src/Tracer/TraceWidget.h \ Src/Utils/CommonActions.h \ diff --git a/src/x64dbg_translations.pro b/src/x64dbg_translations.pro index 3144553678..51980f09bc 100644 --- a/src/x64dbg_translations.pro +++ b/src/x64dbg_translations.pro @@ -230,7 +230,8 @@ SOURCES += \ gui/Src/Tracer/TraceRegisters.cpp \ gui/Src/Tracer/TraceWidget.cpp \ gui/Src/Gui/SystemBreakpointScriptDialog.cpp \ - gui/Src/Tracer/TraceInfoBox.cpp + gui/Src/Tracer/TraceInfoBox.cpp \ + gui/Src/Tracer/TraceManager.cpp HEADERS += \ gui/Src/Exports.h \ @@ -472,7 +473,8 @@ HEADERS += \ gui/Src/Tracer/TraceRegisters.h \ gui/Src/Tracer/TraceWidget.h \ gui/Src/Gui/SystemBreakpointScriptDialog.h \ - gui/Src/Tracer/TraceInfoBox.h + gui/Src/Tracer/TraceInfoBox.h \ + gui/Src/Tracer/TraceManager.h FORMS += \ gui/Src/Gui/AppearanceDialog.ui \ From 77cfffa0aa944f499e6ddaab6ca1f28a2e6267fa Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Tue, 19 Sep 2023 21:58:35 +0800 Subject: [PATCH 11/33] Modify mTraceFile to getTraceFile() for later move to TraceWidget --- src/gui/Src/Tracer/TraceBrowser.cpp | 165 ++++++++++++++-------------- 1 file changed, 80 insertions(+), 85 deletions(-) diff --git a/src/gui/Src/Tracer/TraceBrowser.cpp b/src/gui/Src/Tracer/TraceBrowser.cpp index 219569fbb5..6cf61ea00b 100644 --- a/src/gui/Src/Tracer/TraceBrowser.cpp +++ b/src/gui/Src/Tracer/TraceBrowser.cpp @@ -53,6 +53,7 @@ TraceBrowser::TraceBrowser(QWidget* parent) : AbstractTableView(parent) connect(Bridge::getBridge(), SIGNAL(updateTraceBrowser()), this, SLOT(updateSlot())); connect(Bridge::getBridge(), SIGNAL(openTraceFile(const QString &)), this, SLOT(openSlot(const QString &))); connect(Bridge::getBridge(), SIGNAL(gotoTraceIndex(duint)), this, SLOT(gotoIndexSlot(duint))); + connect(Config(), SIGNAL(tokenizerConfigUpdated()), this, SLOT(tokenizerConfigUpdatedSlot())); connect(this, SIGNAL(selectionChanged(unsigned long long)), this, SLOT(selectionChangedSlot(unsigned long long))); connect(Bridge::getBridge(), SIGNAL(shutdown()), this, SLOT(closeFileSlot())); @@ -292,7 +293,7 @@ QString TraceBrowser::paintContent(QPainter* painter, dsint rowBase, int rowOffs { return ""; } - if(mTraceFile->isError()) + if(getTraceFile()->isError()) { GuiAddLogMessage(tr("An error occurred when reading trace file.\r\n").toUtf8().constData()); mTraceFile->Close(); @@ -314,7 +315,7 @@ QString TraceBrowser::paintContent(QPainter* painter, dsint rowBase, int rowOffs duint index = rowBase + rowOffset; duint cur_addr; REGDUMP reg; - reg = mTraceFile->Registers(index); + reg = getTraceFile()->Registers(index); cur_addr = reg.regcontext.cip; auto traceCount = DbgFunctions()->GetTraceRecordHitCount(cur_addr); bool wIsSelected = (index >= mSelection.fromIndex && index <= mSelection.toIndex); @@ -342,16 +343,16 @@ QString TraceBrowser::paintContent(QPainter* painter, dsint rowBase, int rowOffs std::max(0, std::min(256, mTracedAddressBackgroundColor.blue() + colorDiff))))); } - if(index >= mTraceFile->Length()) + if(index >= getTraceFile()->Length()) return ""; - Instruction_t inst = mTraceFile->Instruction(index); + Instruction_t inst = getTraceFile()->Instruction(index); switch(static_cast(col)) { case Index: { - return mTraceFile->getIndexText(index); + return getTraceFile()->getIndexText(index); } case Address: @@ -563,10 +564,10 @@ QString TraceBrowser::paintContent(QPainter* painter, dsint rowBase, int rowOffs painter->setPen(mConditionalTruePen); int halfRow = getRowHeight() / 2 + 1; int jumpsize = 0; - if((branchType == Instruction_t::Conditional || branchType == Instruction_t::Unconditional) && index < mTraceFile->Length()) + if((branchType == Instruction_t::Conditional || branchType == Instruction_t::Unconditional) && index < getTraceFile()->Length()) { duint next_addr; - next_addr = mTraceFile->Registers(index + 1).regcontext.cip; + next_addr = getTraceFile()->Registers(index + 1).regcontext.cip; if(next_addr < cur_addr) { QPoint wPoints[] = @@ -766,10 +767,10 @@ ZydisTokenizer::InstructionToken TraceBrowser::memoryTokens(unsigned long long a int MemoryOperandsCount; ZydisTokenizer::InstructionToken fakeInstruction = ZydisTokenizer::InstructionToken(); - MemoryOperandsCount = mTraceFile->MemoryAccessCount(atIndex); + MemoryOperandsCount = getTraceFile()->MemoryAccessCount(atIndex); if(MemoryOperandsCount > 0) { - mTraceFile->MemoryAccessInfo(atIndex, MemoryAddress, MemoryOldContent, MemoryNewContent, MemoryIsValid); + getTraceFile()->MemoryAccessInfo(atIndex, MemoryAddress, MemoryOldContent, MemoryNewContent, MemoryIsValid); std::vector tokens; for(int i = 0; i < MemoryOperandsCount; i++) @@ -786,8 +787,8 @@ ZydisTokenizer::InstructionToken TraceBrowser::memoryTokens(unsigned long long a ZydisTokenizer::InstructionToken TraceBrowser::registersTokens(unsigned long long atIndex) { ZydisTokenizer::InstructionToken fakeInstruction = ZydisTokenizer::InstructionToken(); - REGDUMP now = mTraceFile->Registers(atIndex); - REGDUMP next = (atIndex + 1 < mTraceFile->Length()) ? mTraceFile->Registers(atIndex + 1) : now; + REGDUMP now = getTraceFile()->Registers(atIndex); + REGDUMP next = (atIndex + 1 < getTraceFile()->Length()) ? getTraceFile()->Registers(atIndex + 1) : now; std::vector tokens; #define addRegValues(str, reg) if (atIndex ==0 || now.regcontext.##reg != next.regcontext.##reg) { \ @@ -824,8 +825,8 @@ void TraceBrowser::prepareData() if(isFileOpened()) { duint tableOffset = getTableOffset(); - if(mTraceFile->Length() < tableOffset + viewables) - lines = mTraceFile->Length() - tableOffset; + if(getTraceFile()->Length() < tableOffset + viewables) + lines = getTraceFile()->Length() - tableOffset; else lines = viewables; } @@ -837,10 +838,10 @@ void TraceBrowser::setupRightClickContextMenu() mMenuBuilder = new MenuBuilder(this); mCommonActions = new CommonActions(this, getActionHelperFuncs(), [this] { - if(mTraceFile == nullptr || mTraceFile->Progress() < 100 || mTraceFile->Length() == 0) + if(!isFileOpened()) return (duint)0; else - return mTraceFile->Registers(getInitialSelection()).regcontext.cip; + return getTraceFile()->Registers(getInitialSelection()).regcontext.cip; }); QAction* toggleTraceRecording = makeShortcutAction(DIcon("control-record"), tr("Start recording"), SLOT(toggleTraceRecordingSlot()), "ActionToggleRunTrace"); mMenuBuilder->addAction(toggleTraceRecording, [toggleTraceRecording](QMenu*) @@ -861,13 +862,17 @@ void TraceBrowser::setupRightClickContextMenu() }); auto mTraceFileIsNull = [this](QMenu*) { - return mTraceFile == nullptr; + return !isFileOpened(); + }; + auto mTraceFileNotNull = [this](QMenu*) + { + return isFileOpened(); }; mMenuBuilder->addAction(makeAction(DIcon("folder-horizontal-open"), tr("Open"), SLOT(openFileSlot())), mTraceFileIsNull); mMenuBuilder->addMenu(makeMenu(DIcon("recentfiles"), tr("Recent Files")), [this](QMenu * menu) { - if(mTraceFile == nullptr) + if(getTraceFile() == nullptr) { mMRUList->appendMenu(menu); return true; @@ -875,25 +880,15 @@ void TraceBrowser::setupRightClickContextMenu() else return false; }); - mMenuBuilder->addAction(makeAction(DIcon("close"), tr("Close recording"), SLOT(closeFileSlot())), [this](QMenu*) - { - return mTraceFile != nullptr; - }); - mMenuBuilder->addAction(makeAction(DIcon("delete"), tr("Delete recording"), SLOT(closeDeleteSlot())), [this](QMenu*) - { - return mTraceFile != nullptr; - }); + mMenuBuilder->addAction(makeAction(DIcon("close"), tr("Close recording"), SLOT(closeFileSlot())), mTraceFileNotNull); + mMenuBuilder->addAction(makeAction(DIcon("delete"), tr("Delete recording"), SLOT(closeDeleteSlot())), mTraceFileNotNull); mMenuBuilder->addSeparator(); - auto isValid = [this](QMenu*) - { - return mTraceFile != nullptr && mTraceFile->Progress() == 100 && mTraceFile->Length() > 0; - }; auto isDebugging = [this](QMenu*) { - return mTraceFile != nullptr && mTraceFile->Progress() == 100 && mTraceFile->Length() > 0 && DbgIsDebugging(); + return isFileOpened() && DbgIsDebugging(); }; - MenuBuilder* copyMenu = new MenuBuilder(this, isValid); + MenuBuilder* copyMenu = new MenuBuilder(this, mTraceFileNotNull); copyMenu->addAction(makeShortcutAction(DIcon("copy_selection"), tr("&Selection"), SLOT(copySelectionSlot()), "ActionCopy")); copyMenu->addAction(makeAction(DIcon("copy_selection"), tr("Selection to &File"), SLOT(copySelectionToFileSlot()))); copyMenu->addAction(makeAction(DIcon("copy_selection_no_bytes"), tr("Selection (&No Bytes)"), SLOT(copySelectionNoBytesSlot()))); @@ -908,8 +903,8 @@ void TraceBrowser::setupRightClickContextMenu() mMenuBuilder->addMenu(makeMenu(DIcon("copy"), tr("&Copy")), copyMenu); mCommonActions->build(mMenuBuilder, CommonActions::ActionDisasm | CommonActions::ActionBreakpoint | CommonActions::ActionLabel | CommonActions::ActionComment | CommonActions::ActionBookmark); - mMenuBuilder->addAction(makeShortcutAction(DIcon("highlight"), tr("&Highlighting mode"), SLOT(enableHighlightingModeSlot()), "ActionHighlightingMode"), isValid); - mMenuBuilder->addAction(makeShortcutAction(DIcon("helpmnemonic"), tr("Help on mnemonic"), SLOT(mnemonicHelpSlot()), "ActionHelpOnMnemonic"), isValid); + mMenuBuilder->addAction(makeShortcutAction(DIcon("highlight"), tr("&Highlighting mode"), SLOT(enableHighlightingModeSlot()), "ActionHighlightingMode"), mTraceFileNotNull); + mMenuBuilder->addAction(makeShortcutAction(DIcon("helpmnemonic"), tr("Help on mnemonic"), SLOT(mnemonicHelpSlot()), "ActionHelpOnMnemonic"), mTraceFileNotNull); QAction* mnemonicBrief = makeShortcutAction(DIcon("helpbrief"), tr("Show mnemonic brief"), SLOT(mnemonicBriefSlot()), "ActionToggleMnemonicBrief"); mMenuBuilder->addAction(mnemonicBrief, [this, mnemonicBrief](QMenu*) { @@ -919,9 +914,9 @@ void TraceBrowser::setupRightClickContextMenu() mnemonicBrief->setText(tr("Show mnemonic brief")); return true; }); - MenuBuilder* gotoMenu = new MenuBuilder(this, isValid); - gotoMenu->addAction(makeShortcutAction(DIcon("goto"), tr("Index"), SLOT(gotoSlot()), "ActionGotoExpression"), isValid); - gotoMenu->addAction(makeAction(DIcon("arrow-step-rtr"), tr("Function return"), SLOT(rtrSlot())), isValid); + MenuBuilder* gotoMenu = new MenuBuilder(this, mTraceFileNotNull); + gotoMenu->addAction(makeShortcutAction(DIcon("goto"), tr("Index"), SLOT(gotoSlot()), "ActionGotoExpression"), mTraceFileNotNull); + gotoMenu->addAction(makeAction(DIcon("arrow-step-rtr"), tr("Function return"), SLOT(rtrSlot())), mTraceFileNotNull); gotoMenu->addAction(makeShortcutAction(DIcon("previous"), tr("Previous"), SLOT(gotoPreviousSlot()), "ActionGotoPrevious"), [this](QMenu*) { return mHistory.historyHasPrev(); @@ -932,13 +927,13 @@ void TraceBrowser::setupRightClickContextMenu() }); mMenuBuilder->addMenu(makeMenu(DIcon("goto"), tr("Go to")), gotoMenu); - MenuBuilder* searchMenu = new MenuBuilder(this, isValid); + MenuBuilder* searchMenu = new MenuBuilder(this, mTraceFileNotNull); searchMenu->addAction(makeAction(DIcon("search_for_constant"), tr("Address/Constant"), SLOT(searchConstantSlot()))); searchMenu->addAction(makeAction(DIcon("memory-map"), tr("Memory Reference"), SLOT(searchMemRefSlot()))); mMenuBuilder->addMenu(makeMenu(DIcon("search"), tr("&Search")), searchMenu); // The following code adds a menu to view the information about currently selected instruction. When info box is completed, remove me. - MenuBuilder* infoMenu = new MenuBuilder(this, [this, isValid](QMenu * menu) + MenuBuilder* infoMenu = new MenuBuilder(this, [this](QMenu * menu) { duint MemoryAddress[MAX_MEMORY_OPERANDS]; duint MemoryOldContent[MAX_MEMORY_OPERANDS]; @@ -947,13 +942,13 @@ void TraceBrowser::setupRightClickContextMenu() int MemoryOperandsCount; unsigned long long index; - if(!isValid(nullptr)) + if(!isFileOpened()) return false; index = getInitialSelection(); - MemoryOperandsCount = mTraceFile->MemoryAccessCount(index); + MemoryOperandsCount = getTraceFile()->MemoryAccessCount(index); if(MemoryOperandsCount > 0) { - mTraceFile->MemoryAccessInfo(index, MemoryAddress, MemoryOldContent, MemoryNewContent, MemoryIsValid); + getTraceFile()->MemoryAccessInfo(index, MemoryAddress, MemoryOldContent, MemoryNewContent, MemoryIsValid); bool RvaDisplayEnabled = mRvaDisplayEnabled; char nolabel[MAX_LABEL_SIZE]; mRvaDisplayEnabled = false; @@ -988,7 +983,7 @@ void TraceBrowser::contextMenuEvent(QContextMenuEvent* event) void TraceBrowser::mousePressEvent(QMouseEvent* event) { auto index = getIndexOffsetFromY(transY(event->y())) + getTableOffset(); - if(getGuiState() != AbstractTableView::NoState || !mTraceFile || mTraceFile->Progress() < 100) + if(getGuiState() != AbstractTableView::NoState || !getTraceFile() || getTraceFile()->Progress() < 100) { AbstractTableView::mousePressEvent(event); return; @@ -1004,7 +999,7 @@ void TraceBrowser::mousePressEvent(QMouseEvent* event) int columnPosition = 0; if(getColumnIndexFromX(event->x()) == Disassembly) { - tokens = mTraceFile->Instruction(index).tokens; + tokens = getTraceFile()->Instruction(index).tokens; columnPosition = getColumnPosition(Disassembly); } else if(getColumnIndexFromX(event->x()) == TableColumnIndex::Registers) @@ -1070,7 +1065,7 @@ void TraceBrowser::mousePressEvent(QMouseEvent* event) void TraceBrowser::mouseDoubleClickEvent(QMouseEvent* event) { - if(event->button() == Qt::LeftButton && mTraceFile != nullptr && mTraceFile->Progress() == 100) + if(event->button() == Qt::LeftButton && getTraceFile() != nullptr && getTraceFile()->Progress() == 100) { switch(getColumnIndexFromX(event->x())) { @@ -1078,12 +1073,12 @@ void TraceBrowser::mouseDoubleClickEvent(QMouseEvent* event) mCommonActions->followDisassemblySlot(); break; case Address://Address: set RVA - if(mRvaDisplayEnabled && mTraceFile->Registers(getInitialSelection()).regcontext.cip == mRvaDisplayBase) + if(mRvaDisplayEnabled && getTraceFile()->Registers(getInitialSelection()).regcontext.cip == mRvaDisplayBase) mRvaDisplayEnabled = false; else { mRvaDisplayEnabled = true; - mRvaDisplayBase = mTraceFile->Registers(getInitialSelection()).regcontext.cip; + mRvaDisplayBase = getTraceFile()->Registers(getInitialSelection()).regcontext.cip; } reloadData(); break; @@ -1104,7 +1099,7 @@ void TraceBrowser::mouseDoubleClickEvent(QMouseEvent* event) void TraceBrowser::mouseMoveEvent(QMouseEvent* event) { dsint index = getIndexOffsetFromY(transY(event->y())) + getTableOffset(); - if((event->buttons() & Qt::LeftButton) != 0 && getGuiState() == AbstractTableView::NoState && mTraceFile != nullptr && mTraceFile->Progress() == 100) + if((event->buttons() & Qt::LeftButton) != 0 && getGuiState() == AbstractTableView::NoState && getTraceFile() != nullptr && getTraceFile()->Progress() == 100) { if(index < getRowCount()) { @@ -1129,7 +1124,7 @@ void TraceBrowser::keyPressEvent(QKeyEvent* event) int key = event->key(); auto curindex = getInitialSelection(); auto visibleindex = curindex; - if((key == Qt::Key_Up || key == Qt::Key_Down) && mTraceFile && mTraceFile->Progress() == 100) + if((key == Qt::Key_Up || key == Qt::Key_Down) && getTraceFile() && getTraceFile()->Progress() == 100) { if(key == Qt::Key_Up) { @@ -1163,7 +1158,7 @@ void TraceBrowser::keyPressEvent(QKeyEvent* event) } else { - if(getSelectionEnd() + 1 < mTraceFile->Length()) + if(getSelectionEnd() + 1 < getTraceFile()->Length()) { if(event->modifiers() == Qt::ShiftModifier) { @@ -1191,7 +1186,7 @@ void TraceBrowser::selectionChangedSlot(unsigned long long selection) { if(mTraceSyncCpu && isFileOpened()) { - GuiDisasmAt(mTraceFile->Registers(selection).regcontext.cip, 0); + GuiDisasmAt(getTraceFile()->Registers(selection).regcontext.cip, 0); } } @@ -1393,9 +1388,9 @@ void TraceBrowser::mnemonicHelpSlot() { unsigned char data[16] = { 0xCC }; int size; - mTraceFile->OpCode(getInitialSelection(), data, &size); + getTraceFile()->OpCode(getInitialSelection(), data, &size); Zydis zydis; - zydis.Disassemble(mTraceFile->Registers(getInitialSelection()).regcontext.cip, data); + zydis.Disassemble(getTraceFile()->Registers(getInitialSelection()).regcontext.cip, data); DbgCmdExecDirect(QString("mnemonichelp %1").arg(zydis.Mnemonic().c_str())); emit displayLogWidget(); } @@ -1412,13 +1407,13 @@ void TraceBrowser::disasm(unsigned long long index, bool history) void TraceBrowser::gotoSlot() { - if(mTraceFile == nullptr || mTraceFile->Progress() < 100) + if(getTraceFile() == nullptr || getTraceFile()->Progress() < 100) return; GotoDialog gotoDlg(this, false, true, true); if(gotoDlg.exec() == QDialog::Accepted) { auto val = DbgValFromString(gotoDlg.expressionText.toUtf8().constData()); - if(val >= 0 && val < mTraceFile->Length()) + if(val >= 0 && val < getTraceFile()->Length()) disasm(val); } } @@ -1426,7 +1421,7 @@ void TraceBrowser::gotoSlot() void TraceBrowser::rtrSlot() { // Let's hope this search will be fast... - disasm(TraceFileSearchFuncReturn(mTraceFile, getInitialSelection())); + disasm(TraceFileSearchFuncReturn(getTraceFile(), getInitialSelection())); } void TraceBrowser::gotoNextSlot() @@ -1448,7 +1443,7 @@ void TraceBrowser::copyCipSlot() { if(i != getSelectionStart()) clipboard += "\r\n"; - clipboard += ToPtrString(mTraceFile->Registers(i).regcontext.cip); + clipboard += ToPtrString(getTraceFile()->Registers(i).regcontext.cip); } Bridge::CopyToClipboard(clipboard); } @@ -1460,7 +1455,7 @@ void TraceBrowser::copyIndexSlot() { if(i != getSelectionStart()) clipboard += "\r\n"; - clipboard += mTraceFile->getIndexText(i); + clipboard += getTraceFile()->getIndexText(i); } Bridge::CopyToClipboard(clipboard); } @@ -1478,7 +1473,7 @@ void TraceBrowser::pushSelectionInto(bool copyBytes, QTextStream & stream, QText { if(i != getSelectionStart()) stream << "\r\n"; - const Instruction_t & inst = mTraceFile->Instruction(i); + const Instruction_t & inst = getTraceFile()->Instruction(i); duint cur_addr = inst.rva; QString address = getAddrText(cur_addr, 0, addressLen > sizeof(duint) * 2 + 1); QString bytes; @@ -1543,7 +1538,7 @@ void TraceBrowser::pushSelectionInto(bool copyBytes, QTextStream & stream, QText memoryText += token.text; } - stream << mTraceFile->getIndexText(i) + " | " + address.leftJustified(addressLen, QChar(' '), true); + stream << getTraceFile()->getIndexText(i) + " | " + address.leftJustified(addressLen, QChar(' '), true); if(copyBytes) stream << " | " + bytes.leftJustified(bytesLen, QChar(' '), true); stream << " | " + disassembly.leftJustified(disassemblyLen, QChar(' '), true); @@ -1551,7 +1546,7 @@ void TraceBrowser::pushSelectionInto(bool copyBytes, QTextStream & stream, QText stream << " | " + memoryText.leftJustified(memoryLen, QChar(' '), true) + " |" + fullComment; if(htmlStream) { - *htmlStream << QString("%1%2").arg(mTraceFile->getIndexText(i), address.toHtmlEscaped()); + *htmlStream << QString("%1%2").arg(getTraceFile()->getIndexText(i), address.toHtmlEscaped()); if(copyBytes) *htmlStream << QString("%1").arg(bytesHTML); *htmlStream << QString("%1").arg(htmlDisassembly); @@ -1595,7 +1590,7 @@ void TraceBrowser::pushSelectionInto(bool copyBytes, QTextStream & stream, QText void TraceBrowser::copySelectionSlot(bool copyBytes) { - if(mTraceFile == nullptr || mTraceFile->Progress() < 100) + if(getTraceFile() == nullptr || getTraceFile()->Progress() < 100) return; QString selectionString = ""; @@ -1616,7 +1611,7 @@ void TraceBrowser::copySelectionSlot(bool copyBytes) void TraceBrowser::copySelectionToFileSlot(bool copyBytes) { - if(mTraceFile == nullptr || mTraceFile->Progress() < 100) + if(getTraceFile() == nullptr || getTraceFile()->Progress() < 100) return; QString fileName = QFileDialog::getSaveFileName(this, tr("Open File"), "", tr("Text Files (*.txt)")); @@ -1657,7 +1652,7 @@ void TraceBrowser::copySelectionToFileNoBytesSlot() void TraceBrowser::copyDisassemblySlot() { - if(mTraceFile == nullptr || mTraceFile->Progress() < 100) + if(getTraceFile() == nullptr || getTraceFile()->Progress() < 100) return; QString clipboard = ""; @@ -1672,7 +1667,7 @@ void TraceBrowser::copyDisassemblySlot() clipboardHtml += "
"; } RichTextPainter::List richText; - const Instruction_t & inst = mTraceFile->Instruction(i); + const Instruction_t & inst = getTraceFile()->Instruction(i); ZydisTokenizer::TokenToRichText(inst.tokens, richText, 0); RichTextPainter::htmlRichText(richText, &clipboardHtml, clipboard); } @@ -1688,7 +1683,7 @@ void TraceBrowser::copyDisassemblySlot() clipboard += "\r\n"; } RichTextPainter::List richText; - const Instruction_t & inst = mTraceFile->Instruction(i); + const Instruction_t & inst = getTraceFile()->Instruction(i); ZydisTokenizer::TokenToRichText(inst.tokens, richText, 0); RichTextPainter::htmlRichText(richText, nullptr, clipboard); } @@ -1699,12 +1694,12 @@ void TraceBrowser::copyDisassemblySlot() void TraceBrowser::copyRvaSlot() { QString text; - if(mTraceFile == nullptr || mTraceFile->Progress() < 100) + if(getTraceFile() == nullptr || getTraceFile()->Progress() < 100) return; for(unsigned long long i = getSelectionStart(); i <= getSelectionEnd(); i++) { - duint cip = mTraceFile->Registers(i).regcontext.cip; + duint cip = getTraceFile()->Registers(i).regcontext.cip; duint base = DbgFunctions()->ModBaseFromAddr(cip); if(base) { @@ -1724,12 +1719,12 @@ void TraceBrowser::copyRvaSlot() void TraceBrowser::copyFileOffsetSlot() { QString text; - if(mTraceFile == nullptr || mTraceFile->Progress() < 100) + if(getTraceFile() == nullptr || getTraceFile()->Progress() < 100) return; for(unsigned long long i = getSelectionStart(); i <= getSelectionEnd(); i++) { - duint cip = mTraceFile->Registers(i).regcontext.cip; + duint cip = getTraceFile()->Registers(i).regcontext.cip; cip = DbgFunctions()->VaToFileOffset(cip); if(cip) { @@ -1748,7 +1743,7 @@ void TraceBrowser::copyFileOffsetSlot() void TraceBrowser::exportSlot() { - if(mTraceFile == nullptr || mTraceFile->Progress() < 100) + if(getTraceFile() == nullptr || getTraceFile()->Progress() < 100) return; std::vector headers; headers.reserve(getColumnCount()); @@ -1760,26 +1755,26 @@ void TraceBrowser::exportSlot() switch(col) { case Index: - return mTraceFile->getIndexText(row); + return getTraceFile()->getIndexText(row); case Address: { if(!DbgIsDebugging()) - return ToPtrString(mTraceFile->Registers(row).regcontext.cip); + return ToPtrString(getTraceFile()->Registers(row).regcontext.cip); else - return getAddrText(mTraceFile->Registers(row).regcontext.cip, 0, true); + return getAddrText(getTraceFile()->Registers(row).regcontext.cip, 0, true); } case Opcode: { - for(auto i : getRichBytes(mTraceFile->Instruction(row))) + for(auto i : getRichBytes(getTraceFile()->Instruction(row))) temp += i.text; return temp; } case Disassembly: { - for(auto i : mTraceFile->Instruction(row).tokens.tokens) + for(auto i : getTraceFile()->Instruction(row).tokens.tokens) temp += i.text; return temp; } @@ -1804,11 +1799,11 @@ void TraceBrowser::exportSlot() QString comment; bool autoComment = false; char label[MAX_LABEL_SIZE] = ""; - if(GetCommentFormat(mTraceFile->Registers(row).regcontext.cip, comment, &autoComment)) + if(GetCommentFormat(getTraceFile()->Registers(row).regcontext.cip, comment, &autoComment)) { return QString(comment); } - else if(DbgGetLabelAt(mTraceFile->Registers(row).regcontext.cip, SEG_DEFAULT, label)) // label but no comment + else if(DbgGetLabelAt(getTraceFile()->Registers(row).regcontext.cip, SEG_DEFAULT, label)) // label but no comment { return QString(label); } @@ -1835,12 +1830,12 @@ void TraceBrowser::searchConstantSlot() if(!isFileOpened()) return; WordEditDialog constantDlg(this); - duint initialConstant = mTraceFile->Registers(getInitialSelection()).regcontext.cip; + duint initialConstant = getTraceFile()->Registers(getInitialSelection()).regcontext.cip; constantDlg.setup(tr("Constant"), initialConstant, sizeof(duint)); if(constantDlg.exec() == QDialog::Accepted) { auto ticks = GetTickCount(); - int count = TraceFileSearchConstantRange(mTraceFile, constantDlg.getVal(), constantDlg.getVal()); + int count = TraceFileSearchConstantRange(getTraceFile(), constantDlg.getVal(), constantDlg.getVal()); emit displayReferencesWidget(); GuiAddLogMessage(tr("%1 result(s) in %2ms\n").arg(count).arg(GetTickCount() - ticks).toUtf8().constData()); } @@ -1853,7 +1848,7 @@ void TraceBrowser::searchMemRefSlot() if(memRefDlg.exec() == QDialog::Accepted) { auto ticks = GetTickCount(); - int count = TraceFileSearchMemReference(mTraceFile, memRefDlg.getVal()); + int count = TraceFileSearchMemReference(getTraceFile(), memRefDlg.getVal()); emit displayReferencesWidget(); GuiAddLogMessage(tr("%1 result(s) in %2ms\n").arg(count).arg(GetTickCount() - ticks).toUtf8().constData()); } @@ -1861,12 +1856,12 @@ void TraceBrowser::searchMemRefSlot() void TraceBrowser::updateSlot() { - if(mTraceFile && mTraceFile->Progress() == 100) // && this->isVisible() + if(getTraceFile() && getTraceFile()->Progress() == 100) // && this->isVisible() { if(isRecording()) { - mTraceFile->purgeLastPage(); - setRowCount(mTraceFile->Length()); + getTraceFile()->purgeLastPage(); + setRowCount(getTraceFile()->Length()); } } else @@ -1888,6 +1883,6 @@ void TraceBrowser::gotoIndexSlot(duint index) void TraceBrowser::debugdump() { - mTraceFile->buildDumpTo(getInitialSelection()); - mTraceFile->debugdump(getInitialSelection()); + getTraceFile()->buildDumpTo(getInitialSelection()); + getTraceFile()->debugdump(getInitialSelection()); } From ecc5a163c43098c717d8623afde2be1dcda32fa3 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Wed, 20 Sep 2023 09:54:56 +0800 Subject: [PATCH 12/33] temporary --- src/gui/Src/Tracer/TraceManager.cpp | 31 +++++++++++++++++++++++++---- src/gui/Src/Tracer/TraceWidget.cpp | 5 +++++ src/gui/Src/Tracer/TraceWidget.h | 3 +++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/src/gui/Src/Tracer/TraceManager.cpp b/src/gui/Src/Tracer/TraceManager.cpp index e93d818b14..ec368152e4 100644 --- a/src/gui/Src/Tracer/TraceManager.cpp +++ b/src/gui/Src/Tracer/TraceManager.cpp @@ -1,4 +1,7 @@ +#include #include "TraceManager.h" +#include "BrowseDialog.h" +#include "StringUtil.h" #include "MiscUtil.h" TraceManager::TraceManager(QWidget* parent) : QTabWidget(parent) @@ -22,29 +25,49 @@ TraceManager::TraceManager(QWidget* parent) : QTabWidget(parent) connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int))); - open(); + // Add a placeholder tab + QFrame* mPlaceholder = new QFrame(this); + addTab(mPlaceholder, tr("Placeholder")); //TODO: Proper title } void TraceManager::open() { + BrowseDialog browse( + this, + tr("Open trace recording"), + tr("Trace recording"), + tr("Trace recordings (*.%1);;All files (*.*)").arg(ArchValue("trace32", "trace64")), + getDbPath(), + false + ); + if(browse.exec() != QDialog::Accepted) + return; //load the new file TraceWidget* newView = new TraceWidget(this); addTab(newView, tr("Trace")); //TODO: Proper title setCurrentIndex(count() - 1); + emit newView->openSlot(browse.path); } void TraceManager::closeTab(int index) { auto view = qobject_cast(widget(index)); - removeTab(index); if(view) + { + removeTab(index); delete view; + } + else + { + // Placeholder tab + return; + } } void TraceManager::closeAllTabs() { - while(count()) + while(count() > 1) { - closeTab(0); + closeTab(count() - 1); } } diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index 1ef2674f9f..3a04fd980b 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -102,6 +102,11 @@ void TraceWidget::traceSelectionChanged(unsigned long long selection) mGeneralRegs->setRegisters(®isters); } +void TraceWidget::openSlot(const QString & fileName) +{ + emit mTraceWidget->openSlot(fileName); +} + void TraceWidget::updateSlot() { auto fileOpened = mTraceWidget->isFileOpened(); diff --git a/src/gui/Src/Tracer/TraceWidget.h b/src/gui/Src/Tracer/TraceWidget.h index 948ea12037..0676a36030 100644 --- a/src/gui/Src/Tracer/TraceWidget.h +++ b/src/gui/Src/Tracer/TraceWidget.h @@ -28,6 +28,9 @@ class TraceWidget : public QWidget TraceBrowser* getTraceBrowser(); +public slots: + void openSlot(const QString & fileName); + protected slots: void traceSelectionChanged(unsigned long long selection); void updateSlot(); From 3a9e36b729102d4ac0537be38fde9fe4842cf97b Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Wed, 20 Sep 2023 12:06:22 +0800 Subject: [PATCH 13/33] Fix crash in menu builder when opening second tab --- src/gui/Src/Tracer/TraceBrowser.cpp | 2 +- src/gui/Src/Tracer/TraceDump.cpp | 11 ++++++++--- src/gui/Src/Tracer/TraceDump.h | 5 +++-- src/gui/Src/Tracer/TraceManager.cpp | 14 ++++++++++---- src/gui/Src/Tracer/TraceManager.h | 1 + src/gui/Src/Tracer/TraceWidget.cpp | 4 ++-- src/gui/Src/Tracer/TraceWidget.h | 2 +- src/gui/Src/Utils/Configuration.cpp | 13 +++++++++++++ src/gui/Src/Utils/Configuration.h | 1 + 9 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/gui/Src/Tracer/TraceBrowser.cpp b/src/gui/Src/Tracer/TraceBrowser.cpp index 3516ce89bd..2e94cd042f 100644 --- a/src/gui/Src/Tracer/TraceBrowser.cpp +++ b/src/gui/Src/Tracer/TraceBrowser.cpp @@ -51,7 +51,6 @@ TraceBrowser::TraceBrowser(QWidget* parent) : AbstractTableView(parent) Initialize(); connect(Bridge::getBridge(), SIGNAL(updateTraceBrowser()), this, SLOT(updateSlot())); - connect(Bridge::getBridge(), SIGNAL(openTraceFile(const QString &)), this, SLOT(openSlot(const QString &))); connect(Bridge::getBridge(), SIGNAL(gotoTraceIndex(duint)), this, SLOT(gotoIndexSlot(duint))); connect(Config(), SIGNAL(tokenizerConfigUpdated()), this, SLOT(tokenizerConfigUpdatedSlot())); @@ -66,6 +65,7 @@ TraceBrowser::~TraceBrowser() mTraceFile->Close(); delete mTraceFile; } + Config()->unregisterMenuBuilder(mMenuBuilder); } bool TraceBrowser::isFileOpened() const diff --git a/src/gui/Src/Tracer/TraceDump.cpp b/src/gui/Src/Tracer/TraceDump.cpp index 7aaf200a72..53a4c4ba2f 100644 --- a/src/gui/Src/Tracer/TraceDump.cpp +++ b/src/gui/Src/Tracer/TraceDump.cpp @@ -17,7 +17,7 @@ #include "MiscUtil.h" #include "BackgroundFlickerThread.h" -TraceDump::TraceDump(TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent) : mMemoryPage(memoryPage), HexDump(Bridge::getArchitecture(), parent, memoryPage) +TraceDump::TraceDump(Architecture* architecture, TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent) : mMemoryPage(memoryPage), HexDump(architecture, parent, memoryPage) { mDisas = disas; setDrawDebugOnly(false); @@ -30,7 +30,7 @@ TraceDump::TraceDump(TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, Q setView((ViewEnum_t)ConfigUint("HexDump", "DefaultView")); connect(this, SIGNAL(selectionUpdated()), this, SLOT(selectionUpdatedSlot())); - connect(this, SIGNAL(headerButtonReleased(int)), this, SLOT(headerButtonReleasedSlot(int))); + connect(this, SIGNAL(headerButtonReleased(duint)), this, SLOT(headerButtonReleasedSlot(duint))); //mPluginMenu = multiDump->mDumpPluginMenu; @@ -240,6 +240,11 @@ void TraceDump::setupContextMenu() updateShortcuts(); } +TraceDump::~TraceDump() +{ + Config()->unregisterMenuBuilder(mMenuBuilder); +} + void TraceDump::mousePressEvent(QMouseEvent* event) { if(event->buttons() == Qt::MiddleButton) //copy address to clipboard @@ -1457,7 +1462,7 @@ void TraceDump::setView(ViewEnum_t view) } } -void TraceDump::headerButtonReleasedSlot(int colIndex) +void TraceDump::headerButtonReleasedSlot(duint colIndex) { auto callback = mDescriptor[colIndex].columnSwitch; if(callback) diff --git a/src/gui/Src/Tracer/TraceDump.h b/src/gui/Src/Tracer/TraceDump.h index 29a991cf46..b12551e892 100644 --- a/src/gui/Src/Tracer/TraceDump.h +++ b/src/gui/Src/Tracer/TraceDump.h @@ -13,7 +13,8 @@ class TraceDump : public HexDump { Q_OBJECT public: - explicit TraceDump(TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent); + explicit TraceDump(Architecture* architecture, TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent); + ~TraceDump(); void getColumnRichText(duint col, duint rva, RichTextPainter::List & richText) override; QString paintContent(QPainter* painter, duint row, duint col, int x, int y, int w, int h) override; void setupContextMenu(); @@ -78,7 +79,7 @@ public slots: void selectionUpdatedSlot(); void syncWithExpressionSlot(); - void headerButtonReleasedSlot(int colIndex); + void headerButtonReleasedSlot(duint colIndex); private: TraceFileDumpMemoryPage* mMemoryPage; diff --git a/src/gui/Src/Tracer/TraceManager.cpp b/src/gui/Src/Tracer/TraceManager.cpp index ec368152e4..82ec6a6ab2 100644 --- a/src/gui/Src/Tracer/TraceManager.cpp +++ b/src/gui/Src/Tracer/TraceManager.cpp @@ -24,10 +24,11 @@ TraceManager::TraceManager(QWidget* parent) : QTabWidget(parent) setCornerWidget(mCloseAllTabs, Qt::TopLeftCorner); connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int))); + connect(Bridge::getBridge(), SIGNAL(openTraceFile(const QString &)), this, SLOT(openSlot(const QString &))); // Add a placeholder tab QFrame* mPlaceholder = new QFrame(this); - addTab(mPlaceholder, tr("Placeholder")); //TODO: Proper title + addTab(mPlaceholder, tr("Placeholder")); //TODO: This is only to prevent buttons from disappearing } void TraceManager::open() @@ -42,11 +43,16 @@ void TraceManager::open() ); if(browse.exec() != QDialog::Accepted) return; + openSlot(browse.path); +} + +void TraceManager::openSlot(const QString & path) +{ //load the new file - TraceWidget* newView = new TraceWidget(this); - addTab(newView, tr("Trace")); //TODO: Proper title + TraceWidget* newView = new TraceWidget(Bridge::getArchitecture(), this); + addTab(newView, path); //TODO: Proper title setCurrentIndex(count() - 1); - emit newView->openSlot(browse.path); + emit newView->openSlot(path); } void TraceManager::closeTab(int index) diff --git a/src/gui/Src/Tracer/TraceManager.h b/src/gui/Src/Tracer/TraceManager.h index 4e70915895..d0bc68ebc9 100644 --- a/src/gui/Src/Tracer/TraceManager.h +++ b/src/gui/Src/Tracer/TraceManager.h @@ -13,6 +13,7 @@ class TraceManager : public QTabWidget public slots: void open(); + void openSlot(const QString &); void closeTab(int index); void closeAllTabs(); diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index 3a04fd980b..0c145b25af 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -8,7 +8,7 @@ #include "StdTable.h" #include "CPUInfoBox.h" -TraceWidget::TraceWidget(QWidget* parent) : +TraceWidget::TraceWidget(Architecture* architecture, QWidget* parent) : QWidget(parent), ui(new Ui::TraceWidget) { @@ -18,7 +18,7 @@ TraceWidget::TraceWidget(QWidget* parent) : mOverview = new StdTable(this); mInfo = new TraceInfoBox(this); mMemoryPage = new TraceFileDumpMemoryPage(this); - mDump = new TraceDump(mTraceWidget, mMemoryPage, this); + mDump = new TraceDump(architecture, mTraceWidget, mMemoryPage, this); mGeneralRegs = new TraceRegisters(this); //disasm ui->mTopLeftUpperRightFrameLayout->addWidget(mTraceWidget); diff --git a/src/gui/Src/Tracer/TraceWidget.h b/src/gui/Src/Tracer/TraceWidget.h index 0676a36030..d5c834f468 100644 --- a/src/gui/Src/Tracer/TraceWidget.h +++ b/src/gui/Src/Tracer/TraceWidget.h @@ -23,7 +23,7 @@ class TraceWidget : public QWidget Q_OBJECT public: - explicit TraceWidget(QWidget* parent); + explicit TraceWidget(Architecture* architecture, QWidget* parent); ~TraceWidget(); TraceBrowser* getTraceBrowser(); diff --git a/src/gui/Src/Utils/Configuration.cpp b/src/gui/Src/Utils/Configuration.cpp index e09b6c8c7a..9cf54ff573 100644 --- a/src/gui/Src/Utils/Configuration.cpp +++ b/src/gui/Src/Utils/Configuration.cpp @@ -1105,6 +1105,19 @@ void Configuration::registerMainMenuStringList(QList* menu) NamedMenuBuilders.append(MenuMap(menu, menu->size() - 1)); } +void Configuration::unregisterMenuBuilder(MenuBuilder* menu) +{ + QString id = menu->getId(); + for(auto i = NamedMenuBuilders.begin(); i != NamedMenuBuilders.end(); ++i) + { + if(i->type == 0 && i->builder->getId() == id) + { + NamedMenuBuilders.erase(i); + return; + } + } +} + void Configuration::zoomFont(const QString & fontName, QWheelEvent* event) { QPoint numDegrees = event->angleDelta() / 8; diff --git a/src/gui/Src/Utils/Configuration.h b/src/gui/Src/Utils/Configuration.h index fed8983e61..2ce337dad2 100644 --- a/src/gui/Src/Utils/Configuration.h +++ b/src/gui/Src/Utils/Configuration.h @@ -56,6 +56,7 @@ class Configuration : public QObject void writeShortcuts(); void registerMenuBuilder(MenuBuilder* menu, size_t count); void registerMainMenuStringList(QList* menu); + void unregisterMenuBuilder(MenuBuilder* meun); const QColor getColor(const QString & id) const; const bool getBool(const QString & category, const QString & id) const; From 87ca72d3d19952482f593e11697aa1ac9de7aa0f Mon Sep 17 00:00:00 2001 From: Torusrxxx Date: Tue, 26 Sep 2023 09:27:56 +0000 Subject: [PATCH 14/33] Moved trace file reader to trace widget --- src/gui/Src/Tracer/TraceBrowser.cpp | 55 ++++---- src/gui/Src/Tracer/TraceBrowser.h | 2 +- src/gui/Src/Tracer/TraceDump.cpp | 2 +- src/gui/Src/Tracer/TraceDump.h | 2 +- src/gui/Src/Tracer/TraceFileReader.cpp | 9 +- src/gui/Src/Tracer/TraceFileReader.h | 6 +- src/gui/Src/Tracer/TraceManager.cpp | 174 ++++++++++++++----------- src/gui/Src/Tracer/TraceManager.h | 47 +++---- src/gui/Src/Tracer/TraceWidget.cpp | 51 ++++++-- src/gui/Src/Tracer/TraceWidget.h | 7 +- 10 files changed, 202 insertions(+), 153 deletions(-) diff --git a/src/gui/Src/Tracer/TraceBrowser.cpp b/src/gui/Src/Tracer/TraceBrowser.cpp index 2e94cd042f..3c77221b62 100644 --- a/src/gui/Src/Tracer/TraceBrowser.cpp +++ b/src/gui/Src/Tracer/TraceBrowser.cpp @@ -13,9 +13,8 @@ #include "MRUList.h" #include -TraceBrowser::TraceBrowser(QWidget* parent) : AbstractTableView(parent) +TraceBrowser::TraceBrowser(TraceFileReader* traceFile, QWidget* parent) : AbstractTableView(parent), mTraceFile(traceFile) { - mTraceFile = nullptr; addColumnAt(getCharWidth() * 2 * 2 + 8, tr("Index"), false); //index addColumnAt(getCharWidth() * 2 * sizeof(dsint) + 8, tr("Address"), false); //address addColumnAt(getCharWidth() * 2 * 12 + 8, tr("Bytes"), false); //bytes @@ -56,21 +55,17 @@ TraceBrowser::TraceBrowser(QWidget* parent) : AbstractTableView(parent) connect(Config(), SIGNAL(tokenizerConfigUpdated()), this, SLOT(tokenizerConfigUpdatedSlot())); connect(this, SIGNAL(selectionChanged(unsigned long long)), this, SLOT(selectionChangedSlot(unsigned long long))); connect(Bridge::getBridge(), SIGNAL(close()), this, SLOT(closeFileSlot())); + connect(getTraceFile(), SIGNAL(parseFinished()), this, SLOT(parseFinishedSlot())); } TraceBrowser::~TraceBrowser() { - if(mTraceFile) - { - mTraceFile->Close(); - delete mTraceFile; - } Config()->unregisterMenuBuilder(mMenuBuilder); } bool TraceBrowser::isFileOpened() const { - return mTraceFile && mTraceFile->Progress() == 100 && mTraceFile->Length() > 0; + return mTraceFile && mTraceFile->Length() > 0; } bool TraceBrowser::isRecording() @@ -983,7 +978,7 @@ void TraceBrowser::contextMenuEvent(QContextMenuEvent* event) void TraceBrowser::mousePressEvent(QMouseEvent* event) { auto index = getIndexOffsetFromY(transY(event->y())) + getTableOffset(); - if(getGuiState() != AbstractTableView::NoState || !getTraceFile() || getTraceFile()->Progress() < 100) + if(getGuiState() != AbstractTableView::NoState || !getTraceFile()) { AbstractTableView::mousePressEvent(event); return; @@ -1065,7 +1060,7 @@ void TraceBrowser::mousePressEvent(QMouseEvent* event) void TraceBrowser::mouseDoubleClickEvent(QMouseEvent* event) { - if(event->button() == Qt::LeftButton && getTraceFile() != nullptr && getTraceFile()->Progress() == 100) + if(event->button() == Qt::LeftButton && getTraceFile() != nullptr) { switch(getColumnIndexFromX(event->x())) { @@ -1099,7 +1094,7 @@ void TraceBrowser::mouseDoubleClickEvent(QMouseEvent* event) void TraceBrowser::mouseMoveEvent(QMouseEvent* event) { auto index = getIndexOffsetFromY(transY(event->y())) + getTableOffset(); - if((event->buttons() & Qt::LeftButton) != 0 && getGuiState() == AbstractTableView::NoState && getTraceFile() != nullptr && getTraceFile()->Progress() == 100) + if((event->buttons() & Qt::LeftButton) != 0 && getGuiState() == AbstractTableView::NoState && getTraceFile() != nullptr) { if(index < getRowCount()) { @@ -1124,7 +1119,7 @@ void TraceBrowser::keyPressEvent(QKeyEvent* event) int key = event->key(); auto curindex = getInitialSelection(); auto visibleindex = curindex; - if((key == Qt::Key_Up || key == Qt::Key_Down) && getTraceFile() && getTraceFile()->Progress() == 100) + if((key == Qt::Key_Up || key == Qt::Key_Down) && getTraceFile()) { if(key == Qt::Key_Up) { @@ -1308,15 +1303,16 @@ void TraceBrowser::openFileSlot() void TraceBrowser::openSlot(const QString & fileName) { - if(mTraceFile != nullptr) - { - mTraceFile->Close(); - delete mTraceFile; - } - mTraceFile = new TraceFileReader(this); - connect(mTraceFile, SIGNAL(parseFinished()), this, SLOT(parseFinishedSlot())); - mFileName = fileName; - mTraceFile->Open(fileName); + //if(mTraceFile != nullptr) + //{ + // mTraceFile->Close(); + // delete mTraceFile; + //} + //mTraceFile = new TraceFileReader(this); + //connect(mTraceFile, SIGNAL(parseFinished()), this, SLOT(parseFinishedSlot())); + //mFileName = fileName; + //mTraceFile->Open(fileName); + GuiOpenTraceFile(fileName.toUtf8().constData()); // Open in Trace Manager } void TraceBrowser::toggleTraceRecordingSlot() @@ -1324,6 +1320,7 @@ void TraceBrowser::toggleTraceRecordingSlot() toggleTraceRecording(this); } +// TODO: emit close tab event void TraceBrowser::closeFileSlot() { if(isRecording()) @@ -1407,7 +1404,7 @@ void TraceBrowser::disasm(unsigned long long index, bool history) void TraceBrowser::gotoSlot() { - if(getTraceFile() == nullptr || getTraceFile()->Progress() < 100) + if(getTraceFile() == nullptr) return; GotoDialog gotoDlg(this, false, true, true); if(gotoDlg.exec() == QDialog::Accepted) @@ -1590,7 +1587,7 @@ void TraceBrowser::pushSelectionInto(bool copyBytes, QTextStream & stream, QText void TraceBrowser::copySelectionSlot(bool copyBytes) { - if(getTraceFile() == nullptr || getTraceFile()->Progress() < 100) + if(getTraceFile() == nullptr) return; QString selectionString = ""; @@ -1611,7 +1608,7 @@ void TraceBrowser::copySelectionSlot(bool copyBytes) void TraceBrowser::copySelectionToFileSlot(bool copyBytes) { - if(getTraceFile() == nullptr || getTraceFile()->Progress() < 100) + if(getTraceFile() == nullptr) return; QString fileName = QFileDialog::getSaveFileName(this, tr("Open File"), "", tr("Text Files (*.txt)")); @@ -1652,7 +1649,7 @@ void TraceBrowser::copySelectionToFileNoBytesSlot() void TraceBrowser::copyDisassemblySlot() { - if(getTraceFile() == nullptr || getTraceFile()->Progress() < 100) + if(getTraceFile() == nullptr) return; QString clipboard = ""; @@ -1694,7 +1691,7 @@ void TraceBrowser::copyDisassemblySlot() void TraceBrowser::copyRvaSlot() { QString text; - if(getTraceFile() == nullptr || getTraceFile()->Progress() < 100) + if(getTraceFile() == nullptr) return; for(unsigned long long i = getSelectionStart(); i <= getSelectionEnd(); i++) @@ -1719,7 +1716,7 @@ void TraceBrowser::copyRvaSlot() void TraceBrowser::copyFileOffsetSlot() { QString text; - if(getTraceFile() == nullptr || getTraceFile()->Progress() < 100) + if(getTraceFile() == nullptr) return; for(unsigned long long i = getSelectionStart(); i <= getSelectionEnd(); i++) @@ -1743,7 +1740,7 @@ void TraceBrowser::copyFileOffsetSlot() void TraceBrowser::exportSlot() { - if(getTraceFile() == nullptr || getTraceFile()->Progress() < 100) + if(getTraceFile() == nullptr) return; std::vector headers; headers.reserve(getColumnCount()); @@ -1856,7 +1853,7 @@ void TraceBrowser::searchMemRefSlot() void TraceBrowser::updateSlot() { - if(getTraceFile() && getTraceFile()->Progress() == 100) // && this->isVisible() + if(getTraceFile()) // && this->isVisible() { if(isRecording()) { diff --git a/src/gui/Src/Tracer/TraceBrowser.h b/src/gui/Src/Tracer/TraceBrowser.h index 0625237b3c..af9eec1fd5 100644 --- a/src/gui/Src/Tracer/TraceBrowser.h +++ b/src/gui/Src/Tracer/TraceBrowser.h @@ -13,7 +13,7 @@ class TraceBrowser : public AbstractTableView { Q_OBJECT public: - explicit TraceBrowser(QWidget* parent = nullptr); + explicit TraceBrowser(TraceFileReader* traceFile, QWidget* parent = nullptr); ~TraceBrowser() override; QString paintContent(QPainter* painter, duint row, duint col, int x, int y, int w, int h) override; diff --git a/src/gui/Src/Tracer/TraceDump.cpp b/src/gui/Src/Tracer/TraceDump.cpp index 53a4c4ba2f..1d0aefb3b2 100644 --- a/src/gui/Src/Tracer/TraceDump.cpp +++ b/src/gui/Src/Tracer/TraceDump.cpp @@ -265,7 +265,7 @@ void TraceDump::getAttention() thread->start(); } -void TraceDump::printDumpAt(dsint parVA, bool select, bool repaint, bool updateTableOffset) +void TraceDump::printDumpAt(duint parVA, bool select, bool repaint, bool updateTableOffset) { // Modified from Hexdump, removed memory page information // TODO: get memory range from trace instead diff --git a/src/gui/Src/Tracer/TraceDump.h b/src/gui/Src/Tracer/TraceDump.h index b12551e892..9555c547e6 100644 --- a/src/gui/Src/Tracer/TraceDump.h +++ b/src/gui/Src/Tracer/TraceDump.h @@ -23,7 +23,7 @@ class TraceDump : public HexDump void mouseDoubleClickEvent(QMouseEvent* event); void mouseMoveEvent(QMouseEvent* event); void mousePressEvent(QMouseEvent* event); - void printDumpAt(dsint parVA, bool select, bool repaint, bool updateTableOffset); + void printDumpAt(duint parVA, bool select, bool repaint, bool updateTableOffset) override; signals: void displayReferencesWidget(); diff --git a/src/gui/Src/Tracer/TraceFileReader.cpp b/src/gui/Src/Tracer/TraceFileReader.cpp index 6c296fcd73..b76942cd51 100644 --- a/src/gui/Src/Tracer/TraceFileReader.cpp +++ b/src/gui/Src/Tracer/TraceFileReader.cpp @@ -113,10 +113,11 @@ bool TraceFileReader::isError() const } // Return 100 when loading is completed -int TraceFileReader::Progress() const -{ - return progress.load(); -} +// TODO: Trace view should start showing its first instructions as soon as they are loaded +//int TraceFileReader::Progress() const +//{ +// return progress.load(); +//} // Return the count of instructions unsigned long long TraceFileReader::Length() const diff --git a/src/gui/Src/Tracer/TraceFileReader.h b/src/gui/Src/Tracer/TraceFileReader.h index b03b68556e..93d663ec5f 100644 --- a/src/gui/Src/Tracer/TraceFileReader.h +++ b/src/gui/Src/Tracer/TraceFileReader.h @@ -23,7 +23,7 @@ class TraceFileReader : public QObject void Close(); bool Delete(); bool isError() const; - int Progress() const; + //int Progress() const; // TODO: Trace view should start showing its first instructions as soon as they are loaded QString getIndexText(unsigned long long index) const; @@ -32,9 +32,13 @@ class TraceFileReader : public QObject REGDUMP Registers(unsigned long long index); void OpCode(unsigned long long index, unsigned char* buffer, int* opcodeSize); const Instruction_t & Instruction(unsigned long long index); + // Get thread ID DWORD ThreadId(unsigned long long index); + // Get number of memory accesses int MemoryAccessCount(unsigned long long index); + // Get memory access information. Size of these buffers are MAX_MEMORY_OPERANDS. void MemoryAccessInfo(unsigned long long index, duint* address, duint* oldMemory, duint* newMemory, bool* isValid); + // Get hash of EXE duint HashValue() const; const QString & ExePath() const; diff --git a/src/gui/Src/Tracer/TraceManager.cpp b/src/gui/Src/Tracer/TraceManager.cpp index 82ec6a6ab2..e1956c73de 100644 --- a/src/gui/Src/Tracer/TraceManager.cpp +++ b/src/gui/Src/Tracer/TraceManager.cpp @@ -1,79 +1,95 @@ -#include -#include "TraceManager.h" -#include "BrowseDialog.h" -#include "StringUtil.h" -#include "MiscUtil.h" - -TraceManager::TraceManager(QWidget* parent) : QTabWidget(parent) -{ - setMovable(true); - setTabsClosable(true); - - //Open - mOpen = new QPushButton(this); - mOpen->setIcon(DIcon("control-record")); //TODO: New icon - mOpen->setToolTip(tr("Open")); - connect(mOpen, SIGNAL(clicked()), this, SLOT(open())); - setCornerWidget(mOpen, Qt::TopRightCorner); - - //Close All Tabs - mCloseAllTabs = new QPushButton(this); - mCloseAllTabs->setIcon(DIcon("close-all-tabs")); - mCloseAllTabs->setToolTip(tr("Close All Tabs")); - connect(mCloseAllTabs, SIGNAL(clicked()), this, SLOT(closeAllTabs())); - setCornerWidget(mCloseAllTabs, Qt::TopLeftCorner); - - connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int))); - connect(Bridge::getBridge(), SIGNAL(openTraceFile(const QString &)), this, SLOT(openSlot(const QString &))); - - // Add a placeholder tab - QFrame* mPlaceholder = new QFrame(this); - addTab(mPlaceholder, tr("Placeholder")); //TODO: This is only to prevent buttons from disappearing -} - -void TraceManager::open() -{ - BrowseDialog browse( - this, - tr("Open trace recording"), - tr("Trace recording"), - tr("Trace recordings (*.%1);;All files (*.*)").arg(ArchValue("trace32", "trace64")), - getDbPath(), - false - ); - if(browse.exec() != QDialog::Accepted) - return; - openSlot(browse.path); -} - -void TraceManager::openSlot(const QString & path) -{ - //load the new file - TraceWidget* newView = new TraceWidget(Bridge::getArchitecture(), this); - addTab(newView, path); //TODO: Proper title - setCurrentIndex(count() - 1); - emit newView->openSlot(path); -} - -void TraceManager::closeTab(int index) -{ - auto view = qobject_cast(widget(index)); - if(view) - { - removeTab(index); - delete view; - } - else - { - // Placeholder tab - return; - } -} - -void TraceManager::closeAllTabs() -{ - while(count() > 1) - { - closeTab(count() - 1); - } -} +#include +#include "TraceManager.h" +#include "BrowseDialog.h" +#include "StringUtil.h" +#include "MiscUtil.h" + +TraceManager::TraceManager(QWidget* parent) : QTabWidget(parent) +{ + setMovable(true); + setTabsClosable(true); + + //Open + mOpen = new QPushButton(this); + mOpen->setIcon(DIcon("folder-horizontal-open")); //TODO: New icon + mOpen->setToolTip(tr("Open")); + connect(mOpen, SIGNAL(clicked()), this, SLOT(open())); + setCornerWidget(mOpen, Qt::TopRightCorner); + + //Close All Tabs + mCloseAllTabs = new QPushButton(this); + mCloseAllTabs->setIcon(DIcon("close-all-tabs")); + mCloseAllTabs->setToolTip(tr("Close All Tabs")); + connect(mCloseAllTabs, SIGNAL(clicked()), this, SLOT(closeAllTabs())); + setCornerWidget(mCloseAllTabs, Qt::TopLeftCorner); + + connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int))); + connect(Bridge::getBridge(), SIGNAL(openTraceFile(const QString &)), this, SLOT(openSlot(const QString &))); + + // Add a placeholder tab + QFrame* mPlaceholder = new QFrame(this); + addTab(mPlaceholder, tr("Placeholder")); //TODO: This is only to prevent open buttons from disappearing +} + +TraceManager::~TraceManager() +{ + closeAllTabs(); +} + +void TraceManager::open() +{ + BrowseDialog browse( + this, + tr("Open trace recording"), + tr("Trace recording"), + tr("Trace recordings (*.%1);;All files (*.*)").arg(ArchValue("trace32", "trace64")), + getDbPath(), + false + ); + if(browse.exec() != QDialog::Accepted) + return; + openSlot(browse.path); +} + +void TraceManager::openSlot(const QString & path) +{ + //load the new file + TraceWidget* newView = new TraceWidget(Bridge::getArchitecture(), path, this); + addTab(newView, path); //TODO: Proper title + setCurrentIndex(count() - 1); + //emit newView->openSlot(path); +} + +void TraceManager::closeTab(int index) +{ + auto view = qobject_cast(widget(index)); + if(view) + { + removeTab(index); + delete view; + } + else + { + // Placeholder tab + return; + } +} + +void TraceManager::closeAllTabs() +{ + bool closeBack = true; + while(count() > 1) + { + if(closeBack) + { + int beforeTabs = count(); + closeTab(count() - 1); + if(count() == beforeTabs) // Placeholder tab can't be closed, so close tabs before it instead + closeBack = false; + } + else + { + closeTab(0); + } + } +} diff --git a/src/gui/Src/Tracer/TraceManager.h b/src/gui/Src/Tracer/TraceManager.h index d0bc68ebc9..1681f80f55 100644 --- a/src/gui/Src/Tracer/TraceManager.h +++ b/src/gui/Src/Tracer/TraceManager.h @@ -1,23 +1,24 @@ -#pragma once - -#include -#include -#include -#include "TraceWidget.h" - -class TraceManager : public QTabWidget -{ - Q_OBJECT -public: - explicit TraceManager(QWidget* parent = 0); - -public slots: - void open(); - void openSlot(const QString &); - void closeTab(int index); - void closeAllTabs(); - -private: - QPushButton* mOpen; - QPushButton* mCloseAllTabs; -}; +#pragma once + +#include +#include +#include +#include "TraceWidget.h" + +class TraceManager : public QTabWidget +{ + Q_OBJECT +public: + explicit TraceManager(QWidget* parent = 0); + ~TraceManager(); + +public slots: + void open(); + void openSlot(const QString &); + void closeTab(int index); + void closeAllTabs(); + +private: + QPushButton* mOpen; + QPushButton* mCloseAllTabs; +}; diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index 0c145b25af..d0621dde70 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -8,13 +8,15 @@ #include "StdTable.h" #include "CPUInfoBox.h" -TraceWidget::TraceWidget(Architecture* architecture, QWidget* parent) : +TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, QWidget* parent) : QWidget(parent), ui(new Ui::TraceWidget) { ui->setupUi(this); - mTraceWidget = new TraceBrowser(this); + mTraceFile = new TraceFileReader(this); + mTraceFile->Open(fileName); + mTraceWidget = new TraceBrowser(mTraceFile, this); mOverview = new StdTable(this); mInfo = new TraceInfoBox(this); mMemoryPage = new TraceFileDumpMemoryPage(this); @@ -39,6 +41,7 @@ TraceWidget::TraceWidget(Architecture* architecture, QWidget* parent) : connect(button_changeview, SIGNAL(clicked()), mGeneralRegs, SLOT(onChangeFPUViewAction())); connect(mTraceWidget, SIGNAL(selectionChanged(unsigned long long)), this, SLOT(traceSelectionChanged(unsigned long long))); connect(Bridge::getBridge(), SIGNAL(updateTraceBrowser()), this, SLOT(updateSlot())); + connect(mTraceFile, SIGNAL(parseFinished()), this, SLOT(parseFinishedSlot())); mGeneralRegs->SetChangeButton(button_changeview); @@ -73,24 +76,28 @@ TraceWidget::TraceWidget(Architecture* architecture, QWidget* parent) : TraceWidget::~TraceWidget() { + if(mTraceFile) + { + mTraceFile->Close(); + delete mTraceFile; + mTraceFile = nullptr; + } delete ui; } void TraceWidget::traceSelectionChanged(unsigned long long selection) { REGDUMP registers; - TraceFileReader* traceFile; - traceFile = mTraceWidget->getTraceFile(); - if(traceFile != nullptr && traceFile->Progress() == 100) + if(mTraceFile != nullptr) { - if(selection < traceFile->Length()) + if(selection < mTraceFile->Length()) { // update registers view - registers = traceFile->Registers(selection); - mInfo->update(selection, traceFile, registers); + registers = mTraceFile->Registers(selection); + mInfo->update(selection, mTraceFile, registers); // update dump view - traceFile->buildDumpTo(selection); // TODO: sometimes this can be slow - mMemoryPage->setDumpObject(traceFile->getDump()); + mTraceFile->buildDumpTo(selection); // TODO: sometimes this can be slow + mMemoryPage->setDumpObject(mTraceFile->getDump()); mMemoryPage->setSelectedIndex(selection); mDump->reloadData(); } @@ -102,11 +109,31 @@ void TraceWidget::traceSelectionChanged(unsigned long long selection) mGeneralRegs->setRegisters(®isters); } -void TraceWidget::openSlot(const QString & fileName) +void TraceWidget::parseFinishedSlot() { - emit mTraceWidget->openSlot(fileName); + duint initialAddress; + const int count = mTraceFile->MemoryAccessCount(0); + if(count > 0) + { + duint address[MAX_MEMORY_OPERANDS]; + duint oldMemory[MAX_MEMORY_OPERANDS]; + duint newMemory[MAX_MEMORY_OPERANDS]; + bool isValid[MAX_MEMORY_OPERANDS]; + mTraceFile->MemoryAccessInfo(0, address, oldMemory, newMemory, isValid); + initialAddress = address[count - 1]; + } + else + { + initialAddress = mTraceFile->Registers(0).regcontext.cip; + } + mDump->printDumpAt(initialAddress, false, true, true); } +//void TraceWidget::openSlot(const QString & fileName) +//{ +// emit mTraceWidget->openSlot(fileName); +//} + void TraceWidget::updateSlot() { auto fileOpened = mTraceWidget->isFileOpened(); diff --git a/src/gui/Src/Tracer/TraceWidget.h b/src/gui/Src/Tracer/TraceWidget.h index d5c834f468..63ca7cc3ab 100644 --- a/src/gui/Src/Tracer/TraceWidget.h +++ b/src/gui/Src/Tracer/TraceWidget.h @@ -11,6 +11,7 @@ class TraceFileReader; class TraceFileDumpMemoryPage; class TraceInfoBox; class TraceDump; +class TraceFileReader; class StdTable; namespace Ui @@ -23,19 +24,21 @@ class TraceWidget : public QWidget Q_OBJECT public: - explicit TraceWidget(Architecture* architecture, QWidget* parent); + explicit TraceWidget(Architecture* architecture, const QString & fileName, QWidget* parent); ~TraceWidget(); TraceBrowser* getTraceBrowser(); public slots: - void openSlot(const QString & fileName); + //void openSlot(const QString & fileName); protected slots: void traceSelectionChanged(unsigned long long selection); + void parseFinishedSlot(); void updateSlot(); protected: + TraceFileReader* mTraceFile; TraceBrowser* mTraceWidget; TraceInfoBox* mInfo; TraceDump* mDump; From 34bdcb7a51755d2c611538158e0fc024b3383249 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Tue, 26 Sep 2023 18:04:15 +0800 Subject: [PATCH 15/33] Fix memory access by first instruction not in trace --- src/gui/Src/Tracer/TraceFileReader.cpp | 6 +++++- src/gui/Src/Tracer/TraceWidget.cpp | 30 +++++++++++++++----------- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/gui/Src/Tracer/TraceFileReader.cpp b/src/gui/Src/Tracer/TraceFileReader.cpp index b76942cd51..e697effadb 100644 --- a/src/gui/Src/Tracer/TraceFileReader.cpp +++ b/src/gui/Src/Tracer/TraceFileReader.cpp @@ -99,7 +99,8 @@ void TraceFileReader::parseFinishedSlot() progress.store(0); delete parser; parser = nullptr; - buildDump(0); // initialize dump with first instruction + if(Length() > 0) + buildDump(0); // initialize dump with first instruction emit parseFinished(); //for(auto i : fileIndex) @@ -534,6 +535,7 @@ void TraceFileReader::purgeLastPage() unsigned long long index = 0; unsigned long long lastIndex = 0; bool isBlockExist = false; + const bool previousEmpty = Length() == 0; if(length > 0) { index = fileIndex.back().first; @@ -571,6 +573,8 @@ void TraceFileReader::purgeLastPage() fileIndex.back().second.second = index - (lastIndex - 1); error = false; length = index; + if(previousEmpty && length > 0) + buildDump(0); // Initialize dump } catch(std::wstring & errReason) { diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index d0621dde70..7f6310387e 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -112,21 +112,25 @@ void TraceWidget::traceSelectionChanged(unsigned long long selection) void TraceWidget::parseFinishedSlot() { duint initialAddress; - const int count = mTraceFile->MemoryAccessCount(0); - if(count > 0) + if(mTraceFile->Length() > 0) { - duint address[MAX_MEMORY_OPERANDS]; - duint oldMemory[MAX_MEMORY_OPERANDS]; - duint newMemory[MAX_MEMORY_OPERANDS]; - bool isValid[MAX_MEMORY_OPERANDS]; - mTraceFile->MemoryAccessInfo(0, address, oldMemory, newMemory, isValid); - initialAddress = address[count - 1]; - } - else - { - initialAddress = mTraceFile->Registers(0).regcontext.cip; + const int count = mTraceFile->MemoryAccessCount(0); + if(count > 0) + { + // Display source operand + duint address[MAX_MEMORY_OPERANDS]; + duint oldMemory[MAX_MEMORY_OPERANDS]; + duint newMemory[MAX_MEMORY_OPERANDS]; + bool isValid[MAX_MEMORY_OPERANDS]; + mTraceFile->MemoryAccessInfo(0, address, oldMemory, newMemory, isValid); + initialAddress = address[count - 1]; + } + else + { + initialAddress = mTraceFile->Registers(0).regcontext.cip; + } + mDump->printDumpAt(initialAddress, false, true, true); } - mDump->printDumpAt(initialAddress, false, true, true); } //void TraceWidget::openSlot(const QString & fileName) From cd810ad72cc63bf361e393636885ead3413c55dc Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Tue, 26 Sep 2023 18:23:39 +0800 Subject: [PATCH 16/33] revert vcxproj changes --- src/zydis_wrapper/zydis_wrapper.vcxproj | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/zydis_wrapper/zydis_wrapper.vcxproj b/src/zydis_wrapper/zydis_wrapper.vcxproj index cb276c39e1..0097668ee4 100644 --- a/src/zydis_wrapper/zydis_wrapper.vcxproj +++ b/src/zydis_wrapper/zydis_wrapper.vcxproj @@ -1,5 +1,5 @@  - + Debug @@ -26,26 +26,26 @@ StaticLibrary true - v141_xp + v120_xp MultiByte StaticLibrary true - v141_xp + v120_xp MultiByte StaticLibrary false - v141_xp + v120_xp true MultiByte StaticLibrary false - v141_xp + v120_xp true MultiByte From f75c4fd0dfbeaefbff2eb76a537c38026f14be4c Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Mon, 2 Oct 2023 12:38:41 +0800 Subject: [PATCH 17/33] Fixed closing trace tab --- src/gui/Src/Gui/CPUDisassembly.h | 5 +- src/gui/Src/Tracer/TraceBrowser.cpp | 126 ++++++++---------- src/gui/Src/Tracer/TraceBrowser.h | 6 +- src/gui/Src/Tracer/TraceDump.cpp | 192 ++++++++++++++-------------- src/gui/Src/Tracer/TraceDump.h | 2 +- src/gui/Src/Tracer/TraceInfoBox.cpp | 6 +- src/gui/Src/Tracer/TraceManager.cpp | 22 +++- src/gui/Src/Tracer/TraceManager.h | 4 + src/gui/Src/Tracer/TraceWidget.cpp | 13 +- src/gui/Src/Tracer/TraceWidget.h | 4 + 10 files changed, 199 insertions(+), 181 deletions(-) diff --git a/src/gui/Src/Gui/CPUDisassembly.h b/src/gui/Src/Gui/CPUDisassembly.h index 063e22be5d..b7a4e1223f 100644 --- a/src/gui/Src/Gui/CPUDisassembly.h +++ b/src/gui/Src/Gui/CPUDisassembly.h @@ -22,8 +22,6 @@ class CPUDisassembly : public Disassembly // Context menu management void setupRightClickContextMenu(); - void addFollowReferenceMenuItem(QString name, duint value, QMenu* menu, bool isReferences, bool isFollowInCPU); - void setupFollowReferenceMenu(duint va, QMenu* menu, bool isReferences, bool isFollowInCPU); void copySelectionSlot(bool copyBytes); void copySelectionToFileSlot(bool copyBytes); void setSideBar(CPUSideBar* sideBar); @@ -116,6 +114,9 @@ public slots: void pushSelectionInto(bool copyBytes, QTextStream & stream, QTextStream* htmlStream = nullptr); + void addFollowReferenceMenuItem(QString name, duint value, QMenu* menu, bool isReferences, bool isFollowInCPU); + void setupFollowReferenceMenu(duint va, QMenu* menu, bool isReferences, bool isFollowInCPU); + // Menus QMenu* mHwSlotSelectMenu; QMenu* mPluginMenu = nullptr; diff --git a/src/gui/Src/Tracer/TraceBrowser.cpp b/src/gui/Src/Tracer/TraceBrowser.cpp index 3c77221b62..c1c7547f95 100644 --- a/src/gui/Src/Tracer/TraceBrowser.cpp +++ b/src/gui/Src/Tracer/TraceBrowser.cpp @@ -1,4 +1,5 @@ #include "TraceBrowser.h" +#include "TraceWidget.h" #include "TraceFileReader.h" #include "TraceFileSearch.h" #include "RichTextPainter.h" @@ -291,10 +292,7 @@ QString TraceBrowser::paintContent(QPainter* painter, duint row, duint col, int if(getTraceFile()->isError()) { GuiAddLogMessage(tr("An error occurred when reading trace file.\r\n").toUtf8().constData()); - mTraceFile->Close(); - delete mTraceFile; - mTraceFile = nullptr; - setRowCount(0); + emit closeFile(); return ""; } if(mHighlightingMode) @@ -504,54 +502,58 @@ QString TraceBrowser::paintContent(QPainter* painter, duint row, duint col, int case Opcode: { - //draw functions - Function_t funcType; - FUNCTYPE funcFirst = DbgGetFunctionTypeAt(cur_addr); - FUNCTYPE funcLast = DbgGetFunctionTypeAt(cur_addr + inst.length - 1); - HANDLE_RANGE_TYPE(FUNC, funcFirst, funcLast); - switch(funcFirst) + int charwidth = getCharWidth(); + int funcsize = 0; + if(DbgIsDebugging()) { - case FUNC_SINGLE: - funcType = Function_single; - break; - case FUNC_NONE: - funcType = Function_none; - break; - case FUNC_BEGIN: - funcType = Function_start; - break; - case FUNC_MIDDLE: - funcType = Function_middle; - break; - case FUNC_END: - funcType = Function_end; - break; - } - int funcsize = paintFunctionGraphic(painter, x, y, funcType, false); + //draw functions + Function_t funcType; + FUNCTYPE funcFirst = DbgGetFunctionTypeAt(cur_addr); + FUNCTYPE funcLast = DbgGetFunctionTypeAt(cur_addr + inst.length - 1); + HANDLE_RANGE_TYPE(FUNC, funcFirst, funcLast); + switch(funcFirst) + { + case FUNC_SINGLE: + funcType = Function_single; + break; + case FUNC_NONE: + funcType = Function_none; + break; + case FUNC_BEGIN: + funcType = Function_start; + break; + case FUNC_MIDDLE: + funcType = Function_middle; + break; + case FUNC_END: + funcType = Function_end; + break; + } + funcsize = paintFunctionGraphic(painter, x, y, funcType, false); - painter->setPen(mFunctionPen); + painter->setPen(mFunctionPen); - XREFTYPE refType = DbgGetXrefTypeAt(cur_addr); - char indicator; - if(refType == XREF_JMP) - { - indicator = '>'; - } - else if(refType == XREF_CALL) - { - indicator = '$'; - } - else if(funcType != Function_none) - { - indicator = '.'; - } - else - { - indicator = ' '; - } + char indicator; + XREFTYPE refType = DbgGetXrefTypeAt(cur_addr); + if(refType == XREF_JMP) + { + indicator = '>'; + } + else if(refType == XREF_CALL) + { + indicator = '$'; + } + else if(funcType != Function_none) + { + indicator = '.'; + } + else + { + indicator = ' '; + } - int charwidth = getCharWidth(); - painter->drawText(QRect(x + funcsize, y, charwidth, h), Qt::AlignVCenter | Qt::AlignLeft, QString(indicator)); + painter->drawText(QRect(x + funcsize, y, charwidth, h), Qt::AlignVCenter | Qt::AlignLeft, QString(indicator)); + } funcsize += charwidth; //draw jump arrows @@ -838,6 +840,7 @@ void TraceBrowser::setupRightClickContextMenu() else return getTraceFile()->Registers(getInitialSelection()).regcontext.cip; }); + QAction* toggleTraceRecording = makeShortcutAction(DIcon("control-record"), tr("Start recording"), SLOT(toggleTraceRecordingSlot()), "ActionToggleRunTrace"); mMenuBuilder->addAction(toggleTraceRecording, [toggleTraceRecording](QMenu*) { @@ -948,10 +951,7 @@ void TraceBrowser::setupRightClickContextMenu() char nolabel[MAX_LABEL_SIZE]; mRvaDisplayEnabled = false; for(int i = 0; i < MemoryOperandsCount; i++) - { - auto action = menu->addAction(QString("%1: %2 -> %3").arg(getAddrText(MemoryAddress[i], nolabel, false)).arg(ToPtrString(MemoryOldContent[i])).arg(ToPtrString(MemoryNewContent[i]))); - connect(action, SIGNAL(triggered()), this, SLOT(debugdump())); - } + menu->addAction(QString("%1: %2 -> %3").arg(getAddrText(MemoryAddress[i], nolabel, false)).arg(ToPtrString(MemoryOldContent[i])).arg(ToPtrString(MemoryNewContent[i]))); mRvaDisplayEnabled = RvaDisplayEnabled; return true; } @@ -1320,18 +1320,11 @@ void TraceBrowser::toggleTraceRecordingSlot() toggleTraceRecording(this); } -// TODO: emit close tab event void TraceBrowser::closeFileSlot() { if(isRecording()) DbgCmdExecDirect("StopTraceRecording"); - if(mTraceFile != nullptr) - { - mTraceFile->Close(); - delete mTraceFile; - mTraceFile = nullptr; - } - emit Bridge::getBridge()->updateTraceBrowser(); + emit closeFile(); } void TraceBrowser::closeDeleteSlot() @@ -1342,9 +1335,7 @@ void TraceBrowser::closeDeleteSlot() if(isRecording()) DbgCmdExecDirect("StopTraceRecording"); mTraceFile->Delete(); - delete mTraceFile; - mTraceFile = nullptr; - emit Bridge::getBridge()->updateTraceBrowser(); + emit closeFile(); } } @@ -1352,9 +1343,6 @@ void TraceBrowser::parseFinishedSlot() { if(mTraceFile->isError()) { - SimpleErrorBox(this, tr("Error"), tr("Error when opening trace recording")); - delete mTraceFile; - mTraceFile = nullptr; setRowCount(0); } else @@ -1877,9 +1865,3 @@ void TraceBrowser::gotoIndexSlot(duint index) { disasm(index, false); } - -void TraceBrowser::debugdump() -{ - getTraceFile()->buildDumpTo(getInitialSelection()); - getTraceFile()->debugdump(getInitialSelection()); -} diff --git a/src/gui/Src/Tracer/TraceBrowser.h b/src/gui/Src/Tracer/TraceBrowser.h index af9eec1fd5..e03f9814aa 100644 --- a/src/gui/Src/Tracer/TraceBrowser.h +++ b/src/gui/Src/Tracer/TraceBrowser.h @@ -90,7 +90,6 @@ class TraceBrowser : public AbstractTableView QColor mBytesBackgroundColor; QColor mInstructionHighlightColor; - QColor mSelectionColor; QColor mCipBackgroundColor; QColor mCipColor; @@ -150,6 +149,7 @@ class TraceBrowser : public AbstractTableView void displayReferencesWidget(); void displayLogWidget(); void selectionChanged(unsigned long long selection); + void closeFile(); public slots: void openFileSlot(); @@ -187,9 +187,7 @@ public slots: void synchronizeCpuSlot(); void gotoIndexSlot(duint index); - void debugdump(); - -protected: +private: void disasm(unsigned long long index, bool history = true); }; diff --git a/src/gui/Src/Tracer/TraceDump.cpp b/src/gui/Src/Tracer/TraceDump.cpp index 1d0aefb3b2..3773ee7a92 100644 --- a/src/gui/Src/Tracer/TraceDump.cpp +++ b/src/gui/Src/Tracer/TraceDump.cpp @@ -12,7 +12,7 @@ #include "GotoDialog.h" #include "TraceBrowser.h" #include "CommonActions.h" -#include "WordEditDialog.h" +//#include "WordEditDialog.h" #include "CodepageSelectionDialog.h" #include "MiscUtil.h" #include "BackgroundFlickerThread.h" @@ -82,76 +82,79 @@ void TraceDump::setupContextMenu() return DbgMemIsValidReadPtr(ptr); }; - 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); + //TODO: Is it necessary to set memory breakpoints here? + //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")); + //TODO: find in dump + //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")); + //TODO: Do we really need to sync with expression here? + //mMenuBuilder->addAction(makeShortcutAction(DIcon("sync"), tr("&Sync with expression"), SLOT(syncWithExpressionSlot()), "ActionSync")); MenuBuilder* wGotoMenu = new MenuBuilder(this); wGotoMenu->addAction(makeShortcutAction(DIcon("geolocation-goto"), tr("&Expression"), SLOT(gotoExpressionSlot()), "ActionGotoExpression")); @@ -1332,19 +1335,20 @@ void TraceDump::binarySaveToFileSlot() 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(); + //TODO + //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() @@ -1372,18 +1376,18 @@ void TraceDump::selectionUpdatedSlot() GuiAddStatusBarMessage(QString(info + ": " + selStart + " -> " + selEnd + QString().sprintf(" (0x%.8X bytes)\n", getSelectionEnd() - getSelectionStart() + 1)).toUtf8().constData()); } -void TraceDump::syncWithExpressionSlot() -{ - if(!mMemoryPage->isAvailable()) - 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::syncWithExpressionSlot() +//{ +//if(!mMemoryPage->isAvailable()) +//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::setView(ViewEnum_t view) { diff --git a/src/gui/Src/Tracer/TraceDump.h b/src/gui/Src/Tracer/TraceDump.h index 9555c547e6..bf36c5c6c7 100644 --- a/src/gui/Src/Tracer/TraceDump.h +++ b/src/gui/Src/Tracer/TraceDump.h @@ -77,7 +77,7 @@ public slots: void findReferencesSlot(); void selectionUpdatedSlot(); - void syncWithExpressionSlot(); + //void syncWithExpressionSlot();//TODO: Do we really need to sync with expression here? void headerButtonReleasedSlot(duint colIndex); diff --git a/src/gui/Src/Tracer/TraceInfoBox.cpp b/src/gui/Src/Tracer/TraceInfoBox.cpp index f5cf95b18d..b3de15e2b2 100644 --- a/src/gui/Src/Tracer/TraceInfoBox.cpp +++ b/src/gui/Src/Tracer/TraceInfoBox.cpp @@ -35,7 +35,7 @@ TraceInfoBox::~TraceInfoBox() void TraceInfoBox::update(unsigned long long selection, TraceFileReader* traceFile, const REGDUMP & registers) { - int infoline = 0; + duint infoline = 0; Zydis zydis; unsigned char opcode[16]; QString line; @@ -52,7 +52,7 @@ void TraceInfoBox::update(unsigned long long selection, TraceFileReader* traceFi traceFile->MemoryAccessInfo(selection, MemoryAddress, MemoryOldContent, MemoryNewContent, MemoryIsValid); if(zydis.Disassemble(registers.regcontext.cip, opcode, opsize)) { - int opindex; + uint8_t opindex; int memaccessindex; //Jumps if(zydis.IsBranchType(Zydis::BTCondJmp)) @@ -214,7 +214,7 @@ void TraceInfoBox::update(unsigned long long selection, TraceFileReader* traceFi void TraceInfoBox::clear() { setRowCount(4); - for(int i = 0; i < 4; i++) + for(duint i = 0; i < 4; i++) setCellContent(i, 0, QString()); reloadData(); } diff --git a/src/gui/Src/Tracer/TraceManager.cpp b/src/gui/Src/Tracer/TraceManager.cpp index e1956c73de..527dfbdcb8 100644 --- a/src/gui/Src/Tracer/TraceManager.cpp +++ b/src/gui/Src/Tracer/TraceManager.cpp @@ -1,4 +1,5 @@ #include +#include #include "TraceManager.h" #include "BrowseDialog.h" #include "StringUtil.h" @@ -7,7 +8,6 @@ TraceManager::TraceManager(QWidget* parent) : QTabWidget(parent) { setMovable(true); - setTabsClosable(true); //Open mOpen = new QPushButton(this); @@ -56,8 +56,12 @@ void TraceManager::openSlot(const QString & path) //load the new file TraceWidget* newView = new TraceWidget(Bridge::getArchitecture(), path, this); addTab(newView, path); //TODO: Proper title - setCurrentIndex(count() - 1); - //emit newView->openSlot(path); + int index = count() - 1; + setCurrentIndex(index); + connect(newView, &TraceWidget::closeFile, this, [index, this]() + { + closeTab(index); + }); } void TraceManager::closeTab(int index) @@ -66,7 +70,8 @@ void TraceManager::closeTab(int index) if(view) { removeTab(index); - delete view; + mViewsToDelete.append(view); // It needs to return from close event before we can delete + startTimer(100); } else { @@ -93,3 +98,12 @@ void TraceManager::closeAllTabs() } } } + +// These tabs are deleted after the close tab event completes +void TraceManager::timerEvent(QTimerEvent* event) +{ + for(auto & i : mViewsToDelete) + delete i; + mViewsToDelete.clear(); + killTimer(event->timerId()); +} diff --git a/src/gui/Src/Tracer/TraceManager.h b/src/gui/Src/Tracer/TraceManager.h index 1681f80f55..9c49b35135 100644 --- a/src/gui/Src/Tracer/TraceManager.h +++ b/src/gui/Src/Tracer/TraceManager.h @@ -18,7 +18,11 @@ public slots: void closeTab(int index); void closeAllTabs(); +protected: + void timerEvent(QTimerEvent* event) override; + private: QPushButton* mOpen; QPushButton* mCloseAllTabs; + QList mViewsToDelete; }; diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index 7f6310387e..137bf15a78 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -42,6 +42,7 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q connect(mTraceWidget, SIGNAL(selectionChanged(unsigned long long)), this, SLOT(traceSelectionChanged(unsigned long long))); connect(Bridge::getBridge(), SIGNAL(updateTraceBrowser()), this, SLOT(updateSlot())); connect(mTraceFile, SIGNAL(parseFinished()), this, SLOT(parseFinishedSlot())); + connect(mTraceWidget, SIGNAL(closeFile()), this, SLOT(closeFileSlot())); mGeneralRegs->SetChangeButton(button_changeview); @@ -112,7 +113,12 @@ void TraceWidget::traceSelectionChanged(unsigned long long selection) void TraceWidget::parseFinishedSlot() { duint initialAddress; - if(mTraceFile->Length() > 0) + if(mTraceFile->isError()) + { + SimpleErrorBox(this, tr("Error"), tr("Error when opening trace recording")); + emit closeFile(); + } + else if(mTraceFile->Length() > 0) { const int count = mTraceFile->MemoryAccessCount(0); if(count > 0) @@ -146,6 +152,11 @@ void TraceWidget::updateSlot() mInfo->clear(); } +void TraceWidget::closeFileSlot() +{ + emit closeFile(); +} + TraceBrowser* TraceWidget::getTraceBrowser() { return mTraceWidget; diff --git a/src/gui/Src/Tracer/TraceWidget.h b/src/gui/Src/Tracer/TraceWidget.h index 63ca7cc3ab..afb3548aad 100644 --- a/src/gui/Src/Tracer/TraceWidget.h +++ b/src/gui/Src/Tracer/TraceWidget.h @@ -32,10 +32,14 @@ class TraceWidget : public QWidget public slots: //void openSlot(const QString & fileName); +signals: + void closeFile(); + protected slots: void traceSelectionChanged(unsigned long long selection); void parseFinishedSlot(); void updateSlot(); + void closeFileSlot(); protected: TraceFileReader* mTraceFile; From a9645df8e5631a419d6d491c086526222af03874 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Mon, 2 Oct 2023 20:47:54 +0800 Subject: [PATCH 18/33] Fix crash in MenuBuilder getId again --- src/gui/Src/Gui/CustomizeMenuDialog.cpp | 4 ++-- src/gui/Src/Tracer/TraceBrowser.cpp | 1 - src/gui/Src/Tracer/TraceDump.cpp | 3 +-- src/gui/Src/Tracer/TraceDump.h | 2 +- src/gui/Src/Tracer/TraceFileDump.cpp | 10 ++++------ src/gui/Src/Tracer/TraceFileDump.h | 4 ++-- src/gui/Src/Tracer/TraceManager.cpp | 12 +----------- src/gui/Src/Tracer/TraceManager.h | 4 ---- src/gui/Src/Tracer/TraceWidget.cpp | 21 ++++++++------------- src/gui/Src/Tracer/TraceWidget.h | 6 ++---- src/gui/Src/Utils/Configuration.cpp | 8 +++++--- src/gui/Src/Utils/Configuration.h | 4 ++-- src/gui/Src/Utils/MenuBuilder.cpp | 8 +++++++- src/gui/Src/Utils/MenuBuilder.h | 2 ++ 14 files changed, 37 insertions(+), 52 deletions(-) diff --git a/src/gui/Src/Gui/CustomizeMenuDialog.cpp b/src/gui/Src/Gui/CustomizeMenuDialog.cpp index 2e16e2b147..5e4b94b910 100644 --- a/src/gui/Src/Gui/CustomizeMenuDialog.cpp +++ b/src/gui/Src/Gui/CustomizeMenuDialog.cpp @@ -25,9 +25,9 @@ CustomizeMenuDialog::CustomizeMenuDialog(QWidget* parent) : builder = i.builder; id = builder->getId(); } - else //invalid or unsupported type.Continue + else // Invalid or unsupported type. Continue continue; - //Get localized string for the name of individual views + // Get localized string for the name of individual views if(id == "CPUDisassembly") viewName = tr("Disassembler"); else if(id == "CPUDump") diff --git a/src/gui/Src/Tracer/TraceBrowser.cpp b/src/gui/Src/Tracer/TraceBrowser.cpp index c1c7547f95..3a91009cb3 100644 --- a/src/gui/Src/Tracer/TraceBrowser.cpp +++ b/src/gui/Src/Tracer/TraceBrowser.cpp @@ -61,7 +61,6 @@ TraceBrowser::TraceBrowser(TraceFileReader* traceFile, QWidget* parent) : Abstra TraceBrowser::~TraceBrowser() { - Config()->unregisterMenuBuilder(mMenuBuilder); } bool TraceBrowser::isFileOpened() const diff --git a/src/gui/Src/Tracer/TraceDump.cpp b/src/gui/Src/Tracer/TraceDump.cpp index 3773ee7a92..e7b28488f6 100644 --- a/src/gui/Src/Tracer/TraceDump.cpp +++ b/src/gui/Src/Tracer/TraceDump.cpp @@ -19,7 +19,7 @@ TraceDump::TraceDump(Architecture* architecture, TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent) : mMemoryPage(memoryPage), HexDump(architecture, parent, memoryPage) { - mDisas = disas; + //mDisas = disas; //TODO: unused setDrawDebugOnly(false); //mMultiDump = multiDump; @@ -245,7 +245,6 @@ void TraceDump::setupContextMenu() TraceDump::~TraceDump() { - Config()->unregisterMenuBuilder(mMenuBuilder); } void TraceDump::mousePressEvent(QMouseEvent* event) diff --git a/src/gui/Src/Tracer/TraceDump.h b/src/gui/Src/Tracer/TraceDump.h index bf36c5c6c7..ea07ce1995 100644 --- a/src/gui/Src/Tracer/TraceDump.h +++ b/src/gui/Src/Tracer/TraceDump.h @@ -92,7 +92,7 @@ public slots: GotoDialog* mGoto = nullptr; GotoDialog* mGotoOffset = nullptr; - TraceBrowser* mDisas; + //TraceBrowser* mDisas; //CPUMultiDump* mMultiDump; int mAsciiSeparator = 0; diff --git a/src/gui/Src/Tracer/TraceFileDump.cpp b/src/gui/Src/Tracer/TraceFileDump.cpp index 10ff2d340b..7f4cfb514f 100644 --- a/src/gui/Src/Tracer/TraceFileDump.cpp +++ b/src/gui/Src/Tracer/TraceFileDump.cpp @@ -84,10 +84,8 @@ std::vector TraceFileDump::getBytes(duint addr, duint size, unsig i += gap_size - 1; continue; } - else - { - GuiAddLogMessage("impossible!"); - } + //else + // GuiAddLogMessage("impossible!"); } } if(!success) @@ -184,8 +182,8 @@ void TraceFileDump::addMemAccess(duint addr, const void* oldData, const void* ne records[i - 1].first.index = maxIndex; records[i - 1].second.oldData = ((const unsigned char*)oldData)[b]; records[i - 1].second.newData = ((const unsigned char*)newData)[b]; - records[i - 1].second.isWrite = 0; //TODO - records[i - 1].second.isExecute = 0; + //records[i - 1].second.isWrite = 0; //TODO + //records[i - 1].second.isExecute = 0; } dump.insert(records.begin(), records.end()); } diff --git a/src/gui/Src/Tracer/TraceFileDump.h b/src/gui/Src/Tracer/TraceFileDump.h index f0f081ff02..fa9ae56331 100644 --- a/src/gui/Src/Tracer/TraceFileDump.h +++ b/src/gui/Src/Tracer/TraceFileDump.h @@ -22,8 +22,8 @@ class TraceFileDump { unsigned char oldData; unsigned char newData; - unsigned char isWrite; - unsigned char isExecute; + //unsigned char isWrite; + //unsigned char isExecute; }; TraceFileDump(); diff --git a/src/gui/Src/Tracer/TraceManager.cpp b/src/gui/Src/Tracer/TraceManager.cpp index 527dfbdcb8..3770581294 100644 --- a/src/gui/Src/Tracer/TraceManager.cpp +++ b/src/gui/Src/Tracer/TraceManager.cpp @@ -70,8 +70,7 @@ void TraceManager::closeTab(int index) if(view) { removeTab(index); - mViewsToDelete.append(view); // It needs to return from close event before we can delete - startTimer(100); + view->deleteLater(); // It needs to return from close event before we can delete } else { @@ -98,12 +97,3 @@ void TraceManager::closeAllTabs() } } } - -// These tabs are deleted after the close tab event completes -void TraceManager::timerEvent(QTimerEvent* event) -{ - for(auto & i : mViewsToDelete) - delete i; - mViewsToDelete.clear(); - killTimer(event->timerId()); -} diff --git a/src/gui/Src/Tracer/TraceManager.h b/src/gui/Src/Tracer/TraceManager.h index 9c49b35135..1681f80f55 100644 --- a/src/gui/Src/Tracer/TraceManager.h +++ b/src/gui/Src/Tracer/TraceManager.h @@ -18,11 +18,7 @@ public slots: void closeTab(int index); void closeAllTabs(); -protected: - void timerEvent(QTimerEvent* event) override; - private: QPushButton* mOpen; QPushButton* mCloseAllTabs; - QList mViewsToDelete; }; diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index 137bf15a78..ff430e445b 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -16,14 +16,14 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q mTraceFile = new TraceFileReader(this); mTraceFile->Open(fileName); - mTraceWidget = new TraceBrowser(mTraceFile, this); + mTraceBrowser = new TraceBrowser(mTraceFile, this); mOverview = new StdTable(this); mInfo = new TraceInfoBox(this); mMemoryPage = new TraceFileDumpMemoryPage(this); - mDump = new TraceDump(architecture, mTraceWidget, mMemoryPage, this); + mDump = new TraceDump(architecture, mTraceBrowser, mMemoryPage, this); mGeneralRegs = new TraceRegisters(this); //disasm - ui->mTopLeftUpperRightFrameLayout->addWidget(mTraceWidget); + ui->mTopLeftUpperRightFrameLayout->addWidget(mTraceBrowser); //registers mGeneralRegs->setFixedWidth(1000); mGeneralRegs->ShowFPU(true); @@ -39,10 +39,10 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q QPushButton* button_changeview = new QPushButton("", this); button_changeview->setStyleSheet("Text-align:left;padding: 4px;padding-left: 10px;"); connect(button_changeview, SIGNAL(clicked()), mGeneralRegs, SLOT(onChangeFPUViewAction())); - connect(mTraceWidget, SIGNAL(selectionChanged(unsigned long long)), this, SLOT(traceSelectionChanged(unsigned long long))); + connect(mTraceBrowser, SIGNAL(selectionChanged(unsigned long long)), this, SLOT(traceSelectionChanged(unsigned long long))); connect(Bridge::getBridge(), SIGNAL(updateTraceBrowser()), this, SLOT(updateSlot())); connect(mTraceFile, SIGNAL(parseFinished()), this, SLOT(parseFinishedSlot())); - connect(mTraceWidget, SIGNAL(closeFile()), this, SLOT(closeFileSlot())); + connect(mTraceBrowser, SIGNAL(closeFile()), this, SLOT(closeFileSlot())); mGeneralRegs->SetChangeButton(button_changeview); @@ -70,7 +70,7 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q mOverview->setCellContent(1, 0, "world"); mOverview->setCellContent(2, 0, "00000000"); mOverview->setCellContent(3, 0, "TODO: Draw call stack here"); - //mOverview->hide(); + mOverview->hide(); ui->mTopHSplitter->setSizes(QList({1000, 1})); ui->mTopLeftVSplitter->setSizes(QList({1000, 1})); } @@ -141,12 +141,12 @@ void TraceWidget::parseFinishedSlot() //void TraceWidget::openSlot(const QString & fileName) //{ -// emit mTraceWidget->openSlot(fileName); +// emit mTraceBrowser->openSlot(fileName); //} void TraceWidget::updateSlot() { - auto fileOpened = mTraceWidget->isFileOpened(); + auto fileOpened = mTraceBrowser->isFileOpened(); mGeneralRegs->setActive(fileOpened); if(!fileOpened) mInfo->clear(); @@ -156,8 +156,3 @@ void TraceWidget::closeFileSlot() { emit closeFile(); } - -TraceBrowser* TraceWidget::getTraceBrowser() -{ - return mTraceWidget; -} diff --git a/src/gui/Src/Tracer/TraceWidget.h b/src/gui/Src/Tracer/TraceWidget.h index afb3548aad..0db8aaaaab 100644 --- a/src/gui/Src/Tracer/TraceWidget.h +++ b/src/gui/Src/Tracer/TraceWidget.h @@ -27,9 +27,7 @@ class TraceWidget : public QWidget explicit TraceWidget(Architecture* architecture, const QString & fileName, QWidget* parent); ~TraceWidget(); - TraceBrowser* getTraceBrowser(); - -public slots: + //public slots: //void openSlot(const QString & fileName); signals: @@ -43,7 +41,7 @@ protected slots: protected: TraceFileReader* mTraceFile; - TraceBrowser* mTraceWidget; + TraceBrowser* mTraceBrowser; TraceInfoBox* mInfo; TraceDump* mDump; TraceRegisters* mGeneralRegs; diff --git a/src/gui/Src/Utils/Configuration.cpp b/src/gui/Src/Utils/Configuration.cpp index 9cf54ff573..bdd8f859a1 100644 --- a/src/gui/Src/Utils/Configuration.cpp +++ b/src/gui/Src/Utils/Configuration.cpp @@ -1091,18 +1091,20 @@ bool Configuration::shortcutToConfig(const QString & id, const QKeySequence shor return BridgeSettingSet("Shortcuts", _id.toUtf8().constData(), _key.toUtf8().constData()); } -void Configuration::registerMenuBuilder(MenuBuilder* menu, size_t count) +bool Configuration::registerMenuBuilder(MenuBuilder* menu, size_t count) { QString id = menu->getId(); for(const auto & i : NamedMenuBuilders) if(i.type == 0 && i.builder->getId() == id) - return; //already exists + return false; //already exists NamedMenuBuilders.append(MenuMap(menu, count)); + return true; } -void Configuration::registerMainMenuStringList(QList* menu) +bool Configuration::registerMainMenuStringList(QList* menu) { NamedMenuBuilders.append(MenuMap(menu, menu->size() - 1)); + return true; } void Configuration::unregisterMenuBuilder(MenuBuilder* menu) diff --git a/src/gui/Src/Utils/Configuration.h b/src/gui/Src/Utils/Configuration.h index 2ce337dad2..c256c71f1f 100644 --- a/src/gui/Src/Utils/Configuration.h +++ b/src/gui/Src/Utils/Configuration.h @@ -54,8 +54,8 @@ class Configuration : public QObject void writeFonts(); void readShortcuts(); void writeShortcuts(); - void registerMenuBuilder(MenuBuilder* menu, size_t count); - void registerMainMenuStringList(QList* menu); + bool registerMenuBuilder(MenuBuilder* menu, size_t count); + bool registerMainMenuStringList(QList* menu); void unregisterMenuBuilder(MenuBuilder* meun); const QColor getColor(const QString & id) const; diff --git a/src/gui/Src/Utils/MenuBuilder.cpp b/src/gui/Src/Utils/MenuBuilder.cpp index e5fb6687d3..1c9020f2b6 100644 --- a/src/gui/Src/Utils/MenuBuilder.cpp +++ b/src/gui/Src/Utils/MenuBuilder.cpp @@ -9,7 +9,13 @@ void MenuBuilder::loadFromConfig() { this->id = parent()->metaObject()->className(); // Set the ID first because the following subroutine will use it - Config()->registerMenuBuilder(this, _containers.size()); // Register it to the config so the customization dialog can get the text of actions here. + if(Config()->registerMenuBuilder(this, _containers.size())) // Register it to the config so the customization dialog can get the text of actions here. + connect(this, SIGNAL(destroyed()), this, SLOT(unregisterMenuBuilder())); // Remember to unregister menu builder +} + +void MenuBuilder::unregisterMenuBuilder() +{ + Config()->unregisterMenuBuilder(this); } QMenu* MenuBuilder::addMenu(QMenu* submenu, BuildCallback callback) diff --git a/src/gui/Src/Utils/MenuBuilder.h b/src/gui/Src/Utils/MenuBuilder.h index 69802e1690..267469caec 100644 --- a/src/gui/Src/Utils/MenuBuilder.h +++ b/src/gui/Src/Utils/MenuBuilder.h @@ -115,5 +115,7 @@ class MenuBuilder : public QObject BuildCallback _callback; QString id; std::vector _containers; +private slots: + void unregisterMenuBuilder(); }; From 8700a5cdb56741a1b6ba2cfc2fad3bba91daee7a Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Fri, 6 Oct 2023 21:58:05 +0800 Subject: [PATCH 19/33] Remove placeholder tab, add context menu in trace manager --- src/gui/Src/Tracer/TraceBrowser.cpp | 17 ------- src/gui/Src/Tracer/TraceBrowser.h | 2 - src/gui/Src/Tracer/TraceManager.cpp | 72 ++++++++++++++++++----------- src/gui/Src/Tracer/TraceManager.h | 11 +++-- 4 files changed, 53 insertions(+), 49 deletions(-) diff --git a/src/gui/Src/Tracer/TraceBrowser.cpp b/src/gui/Src/Tracer/TraceBrowser.cpp index 3a91009cb3..dbad31b7b2 100644 --- a/src/gui/Src/Tracer/TraceBrowser.cpp +++ b/src/gui/Src/Tracer/TraceBrowser.cpp @@ -42,10 +42,6 @@ TraceBrowser::TraceBrowser(TraceFileReader* traceFile, QWidget* parent) : Abstra mPermanentHighlightingMode = false; mShowMnemonicBrief = false; - mMRUList = new MRUList(this, "Recent Trace Files"); - connect(mMRUList, SIGNAL(openFile(QString)), this, SLOT(openSlot(QString))); - mMRUList->load(); - setupRightClickContextMenu(); Initialize(); @@ -866,17 +862,6 @@ void TraceBrowser::setupRightClickContextMenu() return isFileOpened(); }; - mMenuBuilder->addAction(makeAction(DIcon("folder-horizontal-open"), tr("Open"), SLOT(openFileSlot())), mTraceFileIsNull); - mMenuBuilder->addMenu(makeMenu(DIcon("recentfiles"), tr("Recent Files")), [this](QMenu * menu) - { - if(getTraceFile() == nullptr) - { - mMRUList->appendMenu(menu); - return true; - } - else - return false; - }); mMenuBuilder->addAction(makeAction(DIcon("close"), tr("Close recording"), SLOT(closeFileSlot())), mTraceFileNotNull); mMenuBuilder->addAction(makeAction(DIcon("delete"), tr("Delete recording"), SLOT(closeDeleteSlot())), mTraceFileNotNull); mMenuBuilder->addSeparator(); @@ -1353,8 +1338,6 @@ void TraceBrowser::parseFinishedSlot() tr("Checksum is different for current trace file and the debugee. This probably means you have opened a wrong trace file. This trace file is recorded for \"%1\"").arg(mTraceFile->ExePath())); } setRowCount(mTraceFile->Length()); - mMRUList->addEntry(mFileName); - mMRUList->save(); } setSingleSelection(0); makeVisible(0); diff --git a/src/gui/Src/Tracer/TraceBrowser.h b/src/gui/Src/Tracer/TraceBrowser.h index e03f9814aa..eb121d84fe 100644 --- a/src/gui/Src/Tracer/TraceBrowser.h +++ b/src/gui/Src/Tracer/TraceBrowser.h @@ -6,7 +6,6 @@ class TraceFileReader; class BreakpointMenu; -class MRUList; class CommonActions; class TraceBrowser : public AbstractTableView @@ -83,7 +82,6 @@ class TraceBrowser : public AbstractTableView TraceFileReader* mTraceFile; BreakpointMenu* mBreakpointMenu; - MRUList* mMRUList; QString mFileName; QColor mBytesColor; diff --git a/src/gui/Src/Tracer/TraceManager.cpp b/src/gui/Src/Tracer/TraceManager.cpp index 3770581294..991130faa9 100644 --- a/src/gui/Src/Tracer/TraceManager.cpp +++ b/src/gui/Src/Tracer/TraceManager.cpp @@ -1,7 +1,9 @@ #include #include #include "TraceManager.h" +#include "TraceBrowser.h" #include "BrowseDialog.h" +#include "MRUList.h" #include "StringUtil.h" #include "MiscUtil.h" @@ -9,12 +11,10 @@ TraceManager::TraceManager(QWidget* parent) : QTabWidget(parent) { setMovable(true); - //Open - mOpen = new QPushButton(this); - mOpen->setIcon(DIcon("folder-horizontal-open")); //TODO: New icon - mOpen->setToolTip(tr("Open")); - connect(mOpen, SIGNAL(clicked()), this, SLOT(open())); - setCornerWidget(mOpen, Qt::TopRightCorner); + //MRU + mMRUList = new MRUList(this, "Recent Trace Files"); + connect(mMRUList, SIGNAL(openFile(QString)), this, SLOT(openSlot(QString))); + mMRUList->load(); //Close All Tabs mCloseAllTabs = new QPushButton(this); @@ -25,10 +25,6 @@ TraceManager::TraceManager(QWidget* parent) : QTabWidget(parent) connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int))); connect(Bridge::getBridge(), SIGNAL(openTraceFile(const QString &)), this, SLOT(openSlot(const QString &))); - - // Add a placeholder tab - QFrame* mPlaceholder = new QFrame(this); - addTab(mPlaceholder, tr("Placeholder")); //TODO: This is only to prevent open buttons from disappearing } TraceManager::~TraceManager() @@ -58,6 +54,8 @@ void TraceManager::openSlot(const QString & path) addTab(newView, path); //TODO: Proper title int index = count() - 1; setCurrentIndex(index); + mMRUList->addEntry(path); + mMRUList->save(); connect(newView, &TraceWidget::closeFile, this, [index, this]() { closeTab(index); @@ -72,28 +70,48 @@ void TraceManager::closeTab(int index) removeTab(index); view->deleteLater(); // It needs to return from close event before we can delete } - else +} + +void TraceManager::closeAllTabs() +{ + while(count()) { - // Placeholder tab - return; + closeTab(count() - 1); } } -void TraceManager::closeAllTabs() +void TraceManager::toggleTraceRecording() { - bool closeBack = true; - while(count() > 1) + TraceBrowser::toggleTraceRecording(this); +} + +void TraceManager::contextMenuEvent(QContextMenuEvent* event) +{ + QMenu wMenu; + QAction traceCoverageToggleTraceRecording(tr("Start recording")); + if(TraceBrowser::isRecording()) + { + traceCoverageToggleTraceRecording.setText(tr("Stop trace recording")); + traceCoverageToggleTraceRecording.setIcon(DIcon("control-stop")); + } + else { - if(closeBack) - { - int beforeTabs = count(); - closeTab(count() - 1); - if(count() == beforeTabs) // Placeholder tab can't be closed, so close tabs before it instead - closeBack = false; - } - else - { - closeTab(0); - } + traceCoverageToggleTraceRecording.setText(tr("Start trace recording")); + traceCoverageToggleTraceRecording.setIcon(DIcon("control-record")); } + connect(&traceCoverageToggleTraceRecording, SIGNAL(triggered()), this, SLOT(toggleTraceRecording())); + // Disable toggle trace when not debugging + if(!DbgIsDebugging()) + traceCoverageToggleTraceRecording.setEnabled(false); + wMenu.addAction(&traceCoverageToggleTraceRecording); + + QAction openAction(DIcon("folder-horizontal-open"), tr("Open")); + connect(&openAction, SIGNAL(triggered()), this, SLOT(open())); + wMenu.addAction(&openAction); + + QMenu wMRUMenu(tr("Recent Files")); + mMRUList->appendMenu(&wMRUMenu); + wMenu.addMenu(&wMRUMenu); + + wMenu.exec(mapToGlobal(event->pos())); } diff --git a/src/gui/Src/Tracer/TraceManager.h b/src/gui/Src/Tracer/TraceManager.h index 1681f80f55..cfd27675f9 100644 --- a/src/gui/Src/Tracer/TraceManager.h +++ b/src/gui/Src/Tracer/TraceManager.h @@ -5,20 +5,25 @@ #include #include "TraceWidget.h" +class MRUList; + class TraceManager : public QTabWidget { Q_OBJECT public: - explicit TraceManager(QWidget* parent = 0); - ~TraceManager(); + explicit TraceManager(QWidget* parent = nullptr); + ~TraceManager() override; + + void contextMenuEvent(QContextMenuEvent* event) override; public slots: void open(); void openSlot(const QString &); void closeTab(int index); void closeAllTabs(); + void toggleTraceRecording(); private: - QPushButton* mOpen; + MRUList* mMRUList; QPushButton* mCloseAllTabs; }; From 07fbd1a9af29a0ddb6d29f1a24a87c9ed99449bb Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Sat, 7 Oct 2023 12:28:32 +0800 Subject: [PATCH 20/33] Fixed persistent crash at registerMenuBuilder; adjust menu order; fix hash msgbox --- src/gui/Src/Tracer/TraceBrowser.cpp | 58 +++++++++++--------------- src/gui/Src/Tracer/TraceFileReader.cpp | 4 +- src/gui/Src/Tracer/TraceManager.cpp | 4 +- src/gui/Src/Tracer/TraceWidget.cpp | 8 ++++ src/gui/Src/Utils/Configuration.cpp | 25 ++++++++--- src/gui/Src/Utils/Configuration.h | 12 +++--- 6 files changed, 61 insertions(+), 50 deletions(-) diff --git a/src/gui/Src/Tracer/TraceBrowser.cpp b/src/gui/Src/Tracer/TraceBrowser.cpp index dbad31b7b2..06da2caff1 100644 --- a/src/gui/Src/Tracer/TraceBrowser.cpp +++ b/src/gui/Src/Tracer/TraceBrowser.cpp @@ -836,38 +836,13 @@ void TraceBrowser::setupRightClickContextMenu() return getTraceFile()->Registers(getInitialSelection()).regcontext.cip; }); - QAction* toggleTraceRecording = makeShortcutAction(DIcon("control-record"), tr("Start recording"), SLOT(toggleTraceRecordingSlot()), "ActionToggleRunTrace"); - mMenuBuilder->addAction(toggleTraceRecording, [toggleTraceRecording](QMenu*) + auto mTraceFileNotNull = [](QMenu*) { - if(!DbgIsDebugging()) - return false; - if(isRecording()) - { - toggleTraceRecording->setText(tr("Stop recording")); - toggleTraceRecording->setIcon(DIcon("control-stop")); - } - else - { - toggleTraceRecording->setText(tr("Start recording")); - toggleTraceRecording->setIcon(DIcon("control-record")); - } - return true; - }); - auto mTraceFileIsNull = [this](QMenu*) - { - return !isFileOpened(); + return true; // This should always be true now }; - auto mTraceFileNotNull = [this](QMenu*) - { - return isFileOpened(); - }; - - mMenuBuilder->addAction(makeAction(DIcon("close"), tr("Close recording"), SLOT(closeFileSlot())), mTraceFileNotNull); - mMenuBuilder->addAction(makeAction(DIcon("delete"), tr("Delete recording"), SLOT(closeDeleteSlot())), mTraceFileNotNull); - mMenuBuilder->addSeparator(); auto isDebugging = [this](QMenu*) { - return isFileOpened() && DbgIsDebugging(); + return DbgIsDebugging(); }; MenuBuilder* copyMenu = new MenuBuilder(this, mTraceFileNotNull); @@ -949,6 +924,27 @@ void TraceBrowser::setupRightClickContextMenu() synchronizeCpuAction->setChecked(mTraceSyncCpu); mMenuBuilder->addAction(synchronizeCpuAction); + mMenuBuilder->addSeparator(); + QAction* toggleTraceRecording = makeShortcutAction(DIcon("control-record"), tr("Start recording"), SLOT(toggleTraceRecordingSlot()), "ActionToggleRunTrace"); + mMenuBuilder->addAction(toggleTraceRecording, [toggleTraceRecording](QMenu*) + { + if(!DbgIsDebugging()) + return false; + if(isRecording()) + { + toggleTraceRecording->setText(tr("Stop recording")); + toggleTraceRecording->setIcon(DIcon("control-stop")); + } + else + { + toggleTraceRecording->setText(tr("Start recording")); + toggleTraceRecording->setIcon(DIcon("control-record")); + } + return true; + }); + mMenuBuilder->addAction(makeAction(DIcon("close"), tr("Close recording"), SLOT(closeFileSlot())), mTraceFileNotNull); + mMenuBuilder->addAction(makeAction(DIcon("delete"), tr("Delete recording"), SLOT(closeDeleteSlot())), mTraceFileNotNull); + mMenuBuilder->loadFromConfig(); } @@ -1331,12 +1327,6 @@ void TraceBrowser::parseFinishedSlot() } else { - if(mTraceFile->HashValue() && DbgIsDebugging()) - if(DbgFunctions()->DbGetHash() != mTraceFile->HashValue()) - { - SimpleWarningBox(this, tr("Trace file is recorded for another debuggee"), - tr("Checksum is different for current trace file and the debugee. This probably means you have opened a wrong trace file. This trace file is recorded for \"%1\"").arg(mTraceFile->ExePath())); - } setRowCount(mTraceFile->Length()); } setSingleSelection(0); diff --git a/src/gui/Src/Tracer/TraceFileReader.cpp b/src/gui/Src/Tracer/TraceFileReader.cpp index e697effadb..794c752605 100644 --- a/src/gui/Src/Tracer/TraceFileReader.cpp +++ b/src/gui/Src/Tracer/TraceFileReader.cpp @@ -417,9 +417,9 @@ void TraceFileParser::readFileHeader(TraceFileReader* that) { a = a.mid(2); #ifdef _WIN64 - that->hashValue = a.toLongLong(&ok, 16); + that->hashValue = a.toULongLong(&ok, 16); #else //x86 - that->hashValue = a.toLong(&ok, 16); + that->hashValue = a.toULong(&ok, 16); #endif //_WIN64 if(!ok) that->hashValue = 0; diff --git a/src/gui/Src/Tracer/TraceManager.cpp b/src/gui/Src/Tracer/TraceManager.cpp index 991130faa9..c34b2c24dc 100644 --- a/src/gui/Src/Tracer/TraceManager.cpp +++ b/src/gui/Src/Tracer/TraceManager.cpp @@ -88,7 +88,7 @@ void TraceManager::toggleTraceRecording() void TraceManager::contextMenuEvent(QContextMenuEvent* event) { QMenu wMenu; - QAction traceCoverageToggleTraceRecording(tr("Start recording")); + QAction traceCoverageToggleTraceRecording(tr("Start recording"), this); if(TraceBrowser::isRecording()) { traceCoverageToggleTraceRecording.setText(tr("Stop trace recording")); @@ -105,7 +105,7 @@ void TraceManager::contextMenuEvent(QContextMenuEvent* event) traceCoverageToggleTraceRecording.setEnabled(false); wMenu.addAction(&traceCoverageToggleTraceRecording); - QAction openAction(DIcon("folder-horizontal-open"), tr("Open")); + QAction openAction(DIcon("folder-horizontal-open"), tr("Open"), this); connect(&openAction, SIGNAL(triggered()), this, SLOT(open())); wMenu.addAction(&openAction); diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index ff430e445b..f65f450d4f 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -120,6 +120,14 @@ void TraceWidget::parseFinishedSlot() } else if(mTraceFile->Length() > 0) { + if(mTraceFile->HashValue() && DbgIsDebugging()) + { + if(DbgFunctions()->DbGetHash() != mTraceFile->HashValue()) + { + SimpleWarningBox(this, tr("Trace file is recorded for another debuggee"), + tr("Checksum is different for current trace file and the debugee. This probably means you have opened a wrong trace file. This trace file is recorded for \"%1\"").arg(mTraceFile->ExePath())); + } + } const int count = mTraceFile->MemoryAccessCount(0); if(count > 0) { diff --git a/src/gui/Src/Utils/Configuration.cpp b/src/gui/Src/Utils/Configuration.cpp index bdd8f859a1..c6df3cbc59 100644 --- a/src/gui/Src/Utils/Configuration.cpp +++ b/src/gui/Src/Utils/Configuration.cpp @@ -1095,8 +1095,15 @@ bool Configuration::registerMenuBuilder(MenuBuilder* menu, size_t count) { QString id = menu->getId(); for(const auto & i : NamedMenuBuilders) - if(i.type == 0 && i.builder->getId() == id) - return false; //already exists + { + if(i.type == 0) + { + if(i.builder.isNull()) + continue; + if(i.builder->getId() == id) + return false; //already exists + } + } NamedMenuBuilders.append(MenuMap(menu, count)); return true; } @@ -1112,10 +1119,18 @@ void Configuration::unregisterMenuBuilder(MenuBuilder* menu) QString id = menu->getId(); for(auto i = NamedMenuBuilders.begin(); i != NamedMenuBuilders.end(); ++i) { - if(i->type == 0 && i->builder->getId() == id) + if(i->type == 0) { - NamedMenuBuilders.erase(i); - return; + if(i->builder.isNull()) + { + NamedMenuBuilders.erase(i); + continue; + } + if(i->builder->getId() == id) + { + NamedMenuBuilders.erase(i); + return; + } } } } diff --git a/src/gui/Src/Utils/Configuration.h b/src/gui/Src/Utils/Configuration.h index c256c71f1f..80ca40d00f 100644 --- a/src/gui/Src/Utils/Configuration.h +++ b/src/gui/Src/Utils/Configuration.h @@ -3,9 +3,11 @@ #include #include #include +#include #include #include #include "Imports.h" +#include "MenuBuilder.h" // TODO: declare AppearanceDialog and SettingsDialog entries here, so that you only have to do it in once place #define Config() (Configuration::instance()) @@ -17,7 +19,6 @@ #define ConfigHScrollBarStyle() "QScrollBar:horizontal{border:1px solid grey;background:#f1f1f1;height:10px}QScrollBar::handle:horizontal{background:#aaaaaa;min-width:20px;margin:1px}QScrollBar::add-line:horizontal,QScrollBar::sub-line:horizontal{width:0;height:0}" #define ConfigVScrollBarStyle() "QScrollBar:vertical{border:1px solid grey;background:#f1f1f1;width:10px}QScrollBar::handle:vertical{background:#aaaaaa;min-height:20px;margin:1px}QScrollBar::add-line:vertical,QScrollBar::sub-line:vertical{width:0;height:0}" -class MenuBuilder; class QAction; class QWheelEvent; @@ -89,12 +90,9 @@ class Configuration : public QObject //custom menu maps struct MenuMap { - union - { - QList* mainMenuList; - MenuBuilder* builder; - }; - int type; + QList* mainMenuList; + QPointer builder; + int type; // 0: builder; 1: mainMenuList size_t count; MenuMap() { } From 8dd134f524865d886a435df9341926e5cbfba99e Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Sat, 7 Oct 2023 16:58:51 +0800 Subject: [PATCH 21/33] Add DisableTraceDump setting and clean up --- src/gui/Src/Gui/SettingsDialog.cpp | 7 + src/gui/Src/Gui/SettingsDialog.h | 2 + src/gui/Src/Gui/SettingsDialog.ui | 10 + src/gui/Src/Tracer/TraceDump.cpp | 253 +++---------------------- src/gui/Src/Tracer/TraceDump.h | 4 +- src/gui/Src/Tracer/TraceFileDump.cpp | 84 ++++---- src/gui/Src/Tracer/TraceFileDump.h | 8 +- src/gui/Src/Tracer/TraceFileReader.cpp | 23 +-- src/gui/Src/Tracer/TraceFileReader.h | 1 - src/gui/Src/Tracer/TraceFileSearch.cpp | 5 +- src/gui/Src/Tracer/TraceWidget.cpp | 83 ++++---- src/gui/Src/Tracer/TraceWidget.h | 4 - src/gui/Src/Utils/Configuration.cpp | 1 + 13 files changed, 146 insertions(+), 339 deletions(-) diff --git a/src/gui/Src/Gui/SettingsDialog.cpp b/src/gui/Src/Gui/SettingsDialog.cpp index dffab0f90b..ca1b3fcdc4 100644 --- a/src/gui/Src/Gui/SettingsDialog.cpp +++ b/src/gui/Src/Gui/SettingsDialog.cpp @@ -274,6 +274,7 @@ void SettingsDialog::LoadSettings() GetSettingBool("Gui", "EnableQtHighDpiScaling", &settings.guiEnableQtHighDpiScaling); GetSettingBool("Gui", "WindowLongPath", &settings.guiEnableWindowLongPath); GetSettingBool("Gui", "NoIcons", &settings.guiNoIcons); + GetSettingBool("Gui", "DisableTraceDump", &settings.guiDisableTraceDump); ui->chkFpuRegistersLittleEndian->setChecked(settings.guiFpuRegistersLittleEndian); ui->chkSaveColumnOrder->setChecked(settings.guiSaveColumnOrder); ui->chkNoCloseDialog->setChecked(settings.guiNoCloseDialog); @@ -291,6 +292,7 @@ void SettingsDialog::LoadSettings() ui->chkQtHighDpiScaling->setChecked(settings.guiEnableQtHighDpiScaling); ui->chkWindowLongPath->setChecked(settings.guiEnableWindowLongPath); ui->chkNoIcons->setChecked(settings.guiNoIcons); + ui->chkDisableTraceDump->setChecked(settings.guiDisableTraceDump); //Misc tab if(DbgFunctions()->GetJit) @@ -443,6 +445,7 @@ void SettingsDialog::SaveSettings() BridgeSettingSetUint("Gui", "EnableQtHighDpiScaling", settings.guiEnableQtHighDpiScaling); BridgeSettingSetUint("Gui", "WindowLongPath", settings.guiEnableWindowLongPath); BridgeSettingSetUint("Gui", "NoIcons", settings.guiNoIcons); + BridgeSettingSetUint("Gui", "DisableTraceDump", settings.guiDisableTraceDump); //Misc tab if(DbgFunctions()->GetJit) @@ -1164,3 +1167,7 @@ void SettingsDialog::on_chkNoIcons_toggled(bool checked) settings.guiNoIcons = checked; } +void SettingsDialog::on_chkDisableTraceDump_toggled(bool checked) +{ + settings.guiDisableTraceDump = checked; +} diff --git a/src/gui/Src/Gui/SettingsDialog.h b/src/gui/Src/Gui/SettingsDialog.h index a18e11d1db..4cbfa42e4d 100644 --- a/src/gui/Src/Gui/SettingsDialog.h +++ b/src/gui/Src/Gui/SettingsDialog.h @@ -110,6 +110,7 @@ private slots: void on_chkQtHighDpiScaling_toggled(bool checked); void on_chkWindowLongPath_toggled(bool checked); void on_chkNoIcons_toggled(bool checked); + void on_chkDisableTraceDump_toggled(bool checked); //Misc tab void on_chkSetJIT_stateChanged(int arg1); void on_editSymbolStore_textEdited(const QString & arg1); @@ -248,6 +249,7 @@ private slots: bool guiEnableQtHighDpiScaling = true; bool guiEnableWindowLongPath = false; bool guiNoIcons = false; + bool guiDisableTraceDump = false; //Misc Tab bool miscSetJIT = false; bool miscSymbolStore = false; diff --git a/src/gui/Src/Gui/SettingsDialog.ui b/src/gui/Src/Gui/SettingsDialog.ui index 54c512d31b..6babbf44dc 100644 --- a/src/gui/Src/Gui/SettingsDialog.ui +++ b/src/gui/Src/Gui/SettingsDialog.ui @@ -961,6 +961,16 @@ + + + + Dump in trace view consumes significant memory and CPU resources. It can be disabled if you find it too slow. Already opened trace tabs are not affected. + + + Disable dump in trace view + + + diff --git a/src/gui/Src/Tracer/TraceDump.cpp b/src/gui/Src/Tracer/TraceDump.cpp index e7b28488f6..e5ca6edd5a 100644 --- a/src/gui/Src/Tracer/TraceDump.cpp +++ b/src/gui/Src/Tracer/TraceDump.cpp @@ -8,11 +8,9 @@ #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" @@ -83,71 +81,6 @@ void TraceDump::setupContextMenu() }; //TODO: Is it necessary to set memory breakpoints here? - //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); //TODO: find in dump //mMenuBuilder->addAction(makeShortcutAction(DIcon("search-for"), tr("&Find Pattern..."), SLOT(findPattern()), "ActionFindPattern")); @@ -422,109 +355,6 @@ void TraceDump::mouseDoubleClickEvent(QMouseEvent* event) } } -#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 @@ -535,7 +365,7 @@ void TraceDump::mouseMoveEvent(QMouseEvent* event) auto va = rvaToVa(getItemStartingAddress(x, y)); // Read VA - QToolTip::showText(event->globalPos(), getTooltipForVa(va, 4)); + //QToolTip::showText(event->globalPos(), getTooltipForVa(va, 4)); //TODO: Unsupported HexDump::mouseMoveEvent(event); } @@ -557,31 +387,10 @@ void TraceDump::gotoExpressionSlot() } // TODO: Module information need to be read from trace file -/*void TraceDump::gotoFileOffsetSlot() -{ - if(!mMemoryPage->isAvailable()) - 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); - this->printDumpAt(value, true); -}*/ +//void TraceDump::gotoFileOffsetSlot() +//{ +//... +//} void TraceDump::gotoStartSlot() { @@ -1294,15 +1103,15 @@ void TraceDump::selectionSet(const SELECTIONDATA* selection) 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(); -} +//TODO +//void TraceDump::findReferencesSlot() +//{ +//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::binaryCopySlot() { @@ -1332,23 +1141,23 @@ void TraceDump::binarySaveToFileSlot() } } -void TraceDump::findPattern() -{ - //TODO - //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(); -} +//TODO +//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() { diff --git a/src/gui/Src/Tracer/TraceDump.h b/src/gui/Src/Tracer/TraceDump.h index ea07ce1995..2500b37657 100644 --- a/src/gui/Src/Tracer/TraceDump.h +++ b/src/gui/Src/Tracer/TraceDump.h @@ -72,9 +72,9 @@ public slots: void binaryCopySlot(); void binarySaveToFileSlot(); - void findPattern(); + //void findPattern(); void copyFileOffsetSlot(); - void findReferencesSlot(); + //void findReferencesSlot(); void selectionUpdatedSlot(); //void syncWithExpressionSlot();//TODO: Do we really need to sync with expression here? diff --git a/src/gui/Src/Tracer/TraceFileDump.cpp b/src/gui/Src/Tracer/TraceFileDump.cpp index 7f4cfb514f..c7d20102c3 100644 --- a/src/gui/Src/Tracer/TraceFileDump.cpp +++ b/src/gui/Src/Tracer/TraceFileDump.cpp @@ -190,64 +190,57 @@ void TraceFileDump::addMemAccess(duint addr, const void* oldData, const void* ne // Find continuous memory areas. It is done separate from adding memory accesses because the number of addresses is less than that of memory accesses // TODO: We also need another findMemAreas() which only updates incrementally, when the user steps while tracing -void TraceFileDump::findMemAreas() -{ - memAreas.clear(); - if(dump.empty()) - return; - duint addr = dump.begin()->first.addr; //highest address - duint end = addr; - duint start; - // find first access to addr - do - { - auto it = dump.lower_bound({addr - 1, maxIndex + 1}); - // try to find out if addr-1 is in the dump - for(; it != dump.end(); it = dump.lower_bound({addr - 1, maxIndex + 1})) - { - if(it->first.addr != addr - 1) - break; - addr--; - } - // addr-1 is not in the dump, insert the memory area - start = addr; - memAreas.push_back(std::make_pair(start, end)); - // get to next lowest address - if(it != dump.end()) - { - addr = it->first.addr; - end = addr; - } - else - { - break; - } - } - while(true); -} +// TODO: User interface (UI) +//void TraceFileDump::findMemAreas() +//{ +//memAreas.clear(); +//if(dump.empty()) +//return; +//duint addr = dump.begin()->first.addr; //highest address +//duint end = addr; +//duint start; +//// find first access to addr +//do +//{ +//auto it = dump.lower_bound({addr - 1, maxIndex + 1}); +//// try to find out if addr-1 is in the dump +//for(; it != dump.end(); it = dump.lower_bound({addr - 1, maxIndex + 1})) +//{ +//if(it->first.addr != addr - 1) +//break; +//addr--; +//} +//// addr-1 is not in the dump, insert the memory area +//start = addr; +//memAreas.push_back(std::make_pair(start, end)); +//// get to next lowest address +//if(it != dump.end()) +//{ +//addr = it->first.addr; +//end = addr; +//} +//else +//{ +//break; +//} +//} +//while(true); +//} // TraceFileDumpMemoryPage -TraceFileDumpMemoryPage::TraceFileDumpMemoryPage(QObject* parent) : MemoryPage(0x10000, 0x1000, parent) +TraceFileDumpMemoryPage::TraceFileDumpMemoryPage(TraceFileDump* dump, QObject* parent) : MemoryPage(0x10000, 0x1000, parent) { - QMutexLocker locker(&lock); - dump = nullptr; + this->dump = dump; } void TraceFileDumpMemoryPage::setSelectedIndex(unsigned long long index) { - QMutexLocker locker(&lock); if(dump) selectedIndex = std::min(index, dump->getMaxIndex()); else selectedIndex = 0ull; } -void TraceFileDumpMemoryPage::setDumpObject(TraceFileDump* dump) -{ - QMutexLocker locker(&lock); - this->dump = dump; -} - bool TraceFileDumpMemoryPage::isAvailable() const { return !!this->dump; @@ -260,7 +253,6 @@ unsigned long long TraceFileDumpMemoryPage::getSelectedIndex() const bool TraceFileDumpMemoryPage::read(void* parDest, dsint parRVA, duint parSize) const { - QMutexLocker locker(&lock); if(!dump) return false; auto buffer = dump->getBytes(mBase + parRVA, parSize, selectedIndex); diff --git a/src/gui/Src/Tracer/TraceFileDump.h b/src/gui/Src/Tracer/TraceFileDump.h index fa9ae56331..7b04e905fb 100644 --- a/src/gui/Src/Tracer/TraceFileDump.h +++ b/src/gui/Src/Tracer/TraceFileDump.h @@ -44,8 +44,8 @@ class TraceFileDump { return maxIndex; } - // Find continuous memory areas - void findMemAreas(); + // Find continuous memory areas (currently unused) + // void findMemAreas(); std::vector> memAreas; private: std::map dump; @@ -56,15 +56,13 @@ class TraceFileDumpMemoryPage : public MemoryPage { Q_OBJECT public: - TraceFileDumpMemoryPage(QObject* parent = 0); + TraceFileDumpMemoryPage(TraceFileDump* dump, QObject* parent = nullptr); 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); bool isAvailable() const; private: TraceFileDump* dump; - mutable QMutex lock; unsigned long long selectedIndex = 0ull; }; diff --git a/src/gui/Src/Tracer/TraceFileReader.cpp b/src/gui/Src/Tracer/TraceFileReader.cpp index 794c752605..6849b3cef8 100644 --- a/src/gui/Src/Tracer/TraceFileReader.cpp +++ b/src/gui/Src/Tracer/TraceFileReader.cpp @@ -99,7 +99,7 @@ void TraceFileReader::parseFinishedSlot() progress.store(0); delete parser; parser = nullptr; - if(Length() > 0) + if(Length() > 0 && !Config()->getBool("Gui", "DisableTraceDump")) buildDump(0); // initialize dump with first instruction emit parseFinished(); @@ -573,7 +573,7 @@ void TraceFileReader::purgeLastPage() fileIndex.back().second.second = index - (lastIndex - 1); error = false; length = index; - if(previousEmpty && length > 0) + if(previousEmpty && length > 0 && !Config()->getBool("Gui", "DisableTraceDump")) buildDump(0); // Initialize dump } catch(std::wstring & errReason) @@ -698,22 +698,6 @@ void TraceFileReader::buildDumpTo(unsigned long long index) } } -void TraceFileReader::debugdump(unsigned long long index) //TODO: remove me -{ - dump.findMemAreas(); - for(auto c : dump.memAreas) - { - auto mData = dump.getBytes(c.first, c.second - c.first + 1, index); - QString data; - for(size_t i = 0; i < mData.size(); i++) - { - byte_t ch = mData.at(i); - data += QString().sprintf("%02X", ch); - } - GuiAddLogMessage(QString("dump:%1-%2:%3\n").arg(ToPtrString(c.first)).arg(ToPtrString(c.second)).arg(data).toUtf8()); - } -} - std::vector TraceFileReader::getReferences(duint startAddr, duint endAddr) const { return dump.getReferences(startAddr, endAddr); @@ -890,12 +874,13 @@ void TraceFilePage::MemoryAccessInfo(unsigned long long index, duint* address, d address[i] = memoryAddress.at(base + i); oldMemory[i] = this->oldMemory.at(base + i); newMemory[i] = this->newMemory.at(base + i); - isValid[i] = true; // proposed flag + isValid[i] = true; // TODO: proposed flag } } void TraceFilePage::updateInstructions() { + // Just clear them, they will be updated when accessed instructions.clear(); } diff --git a/src/gui/Src/Tracer/TraceFileReader.h b/src/gui/Src/Tracer/TraceFileReader.h index 93d663ec5f..be4aa3496b 100644 --- a/src/gui/Src/Tracer/TraceFileReader.h +++ b/src/gui/Src/Tracer/TraceFileReader.h @@ -46,7 +46,6 @@ class TraceFileReader : public QObject void buildDumpTo(unsigned long long index); std::vector getReferences(duint startAddr, duint endAddr) const; - void debugdump(unsigned long long index); TraceFileDump* getDump(); signals: diff --git a/src/gui/Src/Tracer/TraceFileSearch.cpp b/src/gui/Src/Tracer/TraceFileSearch.cpp index ce0ea20b84..21743cd7d1 100644 --- a/src/gui/Src/Tracer/TraceFileSearch.cpp +++ b/src/gui/Src/Tracer/TraceFileSearch.cpp @@ -1,8 +1,9 @@ +#include #include "TraceFileReader.h" #include "TraceFileSearch.h" #include "zydis_wrapper.h" #include "StringUtil.h" -#include +#include "Configuration.h" static bool inRange(duint value, duint start, duint end) { @@ -97,7 +98,7 @@ int TraceFileSearchMemReference(TraceFileReader* file, duint address) GuiReferenceAddColumn(100, QCoreApplication::translate("TraceFileSearch", "Disassembly").toUtf8().constData()); GuiReferenceAddCommand(QCoreApplication::translate("TraceFileSearch", "Follow index in trace").toUtf8().constData(), "gototrace 0x$1"); GuiReferenceSetRowCount(0); - bool useTraceDump = true; + bool useTraceDump = !Config()->getBool("Gui", "DisableTraceDump"); if(useTraceDump) { diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index f65f450d4f..d2571467d7 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -19,8 +19,16 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q mTraceBrowser = new TraceBrowser(mTraceFile, this); mOverview = new StdTable(this); mInfo = new TraceInfoBox(this); - mMemoryPage = new TraceFileDumpMemoryPage(this); - mDump = new TraceDump(architecture, mTraceBrowser, mMemoryPage, this); + if(!Config()->getBool("Gui", "DisableTraceDump")) + { + mMemoryPage = new TraceFileDumpMemoryPage(mTraceFile->getDump(), this); + mDump = new TraceDump(architecture, mTraceBrowser, mMemoryPage, this); + } + else + { + mMemoryPage = nullptr; + mDump = nullptr; + } mGeneralRegs = new TraceRegisters(this); //disasm ui->mTopLeftUpperRightFrameLayout->addWidget(mTraceBrowser); @@ -40,7 +48,6 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q button_changeview->setStyleSheet("Text-align:left;padding: 4px;padding-left: 10px;"); connect(button_changeview, SIGNAL(clicked()), mGeneralRegs, SLOT(onChangeFPUViewAction())); connect(mTraceBrowser, SIGNAL(selectionChanged(unsigned long long)), this, SLOT(traceSelectionChanged(unsigned long long))); - connect(Bridge::getBridge(), SIGNAL(updateTraceBrowser()), this, SLOT(updateSlot())); connect(mTraceFile, SIGNAL(parseFinished()), this, SLOT(parseFinishedSlot())); connect(mTraceBrowser, SIGNAL(closeFile()), this, SLOT(closeFileSlot())); @@ -56,8 +63,8 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q ui->mTopLeftLowerFrame->setMinimumHeight(height + 2); //dump - //ui->mTopLeftLowerFrameLayout->addWidget(mDump); - ui->mBotLeftFrameLayout->addWidget(mDump); + if(mDump) + ui->mBotLeftFrameLayout->addWidget(mDump); //overview ui->mBotRightFrameLayout->addWidget(mOverview); @@ -73,6 +80,13 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q mOverview->hide(); ui->mTopHSplitter->setSizes(QList({1000, 1})); ui->mTopLeftVSplitter->setSizes(QList({1000, 1})); + + mTraceBrowser->setAccessibleName(tr("Disassembly")); + mOverview->setAccessibleName(tr("Stack")); + upperScrollArea->setAccessibleName(tr("Registers")); + if(mDump) + mDump->setAccessibleName(tr("Dump")); + mInfo->setAccessibleName(tr("InfoBox")); } TraceWidget::~TraceWidget() @@ -97,16 +111,16 @@ void TraceWidget::traceSelectionChanged(unsigned long long selection) registers = mTraceFile->Registers(selection); mInfo->update(selection, mTraceFile, registers); // update dump view - mTraceFile->buildDumpTo(selection); // TODO: sometimes this can be slow - mMemoryPage->setDumpObject(mTraceFile->getDump()); - mMemoryPage->setSelectedIndex(selection); - mDump->reloadData(); + if(mDump) + { + mTraceFile->buildDumpTo(selection); // TODO: sometimes this can be slow // TODO: Is it a good idea to build dump index just when opening the file? + mMemoryPage->setSelectedIndex(selection); + mDump->reloadData(); + } } else memset(®isters, 0, sizeof(registers)); } - else - mMemoryPage->setDumpObject(nullptr); mGeneralRegs->setRegisters(®isters); } @@ -128,38 +142,31 @@ void TraceWidget::parseFinishedSlot() tr("Checksum is different for current trace file and the debugee. This probably means you have opened a wrong trace file. This trace file is recorded for \"%1\"").arg(mTraceFile->ExePath())); } } - const int count = mTraceFile->MemoryAccessCount(0); - if(count > 0) - { - // Display source operand - duint address[MAX_MEMORY_OPERANDS]; - duint oldMemory[MAX_MEMORY_OPERANDS]; - duint newMemory[MAX_MEMORY_OPERANDS]; - bool isValid[MAX_MEMORY_OPERANDS]; - mTraceFile->MemoryAccessInfo(0, address, oldMemory, newMemory, isValid); - initialAddress = address[count - 1]; - } - else + if(mDump) { - initialAddress = mTraceFile->Registers(0).regcontext.cip; + // Setting the initial address of dump view + const int count = mTraceFile->MemoryAccessCount(0); + if(count > 0) + { + // Display source operand + duint address[MAX_MEMORY_OPERANDS]; + duint oldMemory[MAX_MEMORY_OPERANDS]; + duint newMemory[MAX_MEMORY_OPERANDS]; + bool isValid[MAX_MEMORY_OPERANDS]; + mTraceFile->MemoryAccessInfo(0, address, oldMemory, newMemory, isValid); + initialAddress = address[count - 1]; + } + else + { + // No memory operands, so display opcode instead + initialAddress = mTraceFile->Registers(0).regcontext.cip; + } + mDump->printDumpAt(initialAddress, false, true, true); } - mDump->printDumpAt(initialAddress, false, true, true); + mGeneralRegs->setActive(true); } } -//void TraceWidget::openSlot(const QString & fileName) -//{ -// emit mTraceBrowser->openSlot(fileName); -//} - -void TraceWidget::updateSlot() -{ - auto fileOpened = mTraceBrowser->isFileOpened(); - mGeneralRegs->setActive(fileOpened); - if(!fileOpened) - mInfo->clear(); -} - void TraceWidget::closeFileSlot() { emit closeFile(); diff --git a/src/gui/Src/Tracer/TraceWidget.h b/src/gui/Src/Tracer/TraceWidget.h index 0db8aaaaab..2782577f6d 100644 --- a/src/gui/Src/Tracer/TraceWidget.h +++ b/src/gui/Src/Tracer/TraceWidget.h @@ -27,16 +27,12 @@ class TraceWidget : public QWidget explicit TraceWidget(Architecture* architecture, const QString & fileName, QWidget* parent); ~TraceWidget(); - //public slots: - //void openSlot(const QString & fileName); - signals: void closeFile(); protected slots: void traceSelectionChanged(unsigned long long selection); void parseFinishedSlot(); - void updateSlot(); void closeFileSlot(); protected: diff --git a/src/gui/Src/Utils/Configuration.cpp b/src/gui/Src/Utils/Configuration.cpp index c6df3cbc59..6b6db13d35 100644 --- a/src/gui/Src/Utils/Configuration.cpp +++ b/src/gui/Src/Utils/Configuration.cpp @@ -292,6 +292,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false) guiBool.insert("AutoFollowInStack", true); guiBool.insert("EnableQtHighDpiScaling", true); guiBool.insert("Topmost", false); + guiBool.insert("DisableTraceDump", false); //Named menu settings insertMenuBuilderBools(&guiBool, "CPUDisassembly", 50); //CPUDisassembly insertMenuBuilderBools(&guiBool, "CPUDump", 50); //CPUDump From be9d09040ace57fc315c84af68c4323c74ee564b Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Tue, 17 Oct 2023 11:19:29 +0800 Subject: [PATCH 22/33] Add browse in explorer action in trace view --- src/gui/Src/Tracer/TraceBrowser.cpp | 27 ++++++++++++-------------- src/gui/Src/Tracer/TraceBrowser.h | 1 + src/gui/Src/Tracer/TraceFileReader.cpp | 5 +++++ src/gui/Src/Tracer/TraceFileReader.h | 1 + 4 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/gui/Src/Tracer/TraceBrowser.cpp b/src/gui/Src/Tracer/TraceBrowser.cpp index 06da2caff1..8921ff585a 100644 --- a/src/gui/Src/Tracer/TraceBrowser.cpp +++ b/src/gui/Src/Tracer/TraceBrowser.cpp @@ -828,19 +828,16 @@ void TraceBrowser::prepareData() void TraceBrowser::setupRightClickContextMenu() { mMenuBuilder = new MenuBuilder(this); - mCommonActions = new CommonActions(this, getActionHelperFuncs(), [this] + mCommonActions = new CommonActions(this, getActionHelperFuncs(), [this]() { - if(!isFileOpened()) - return (duint)0; - else - return getTraceFile()->Registers(getInitialSelection()).regcontext.cip; + return getTraceFile()->Registers(getInitialSelection()).regcontext.cip; }); auto mTraceFileNotNull = [](QMenu*) { return true; // This should always be true now }; - auto isDebugging = [this](QMenu*) + auto isDebugging = [](QMenu*) { return DbgIsDebugging(); }; @@ -944,6 +941,7 @@ void TraceBrowser::setupRightClickContextMenu() }); mMenuBuilder->addAction(makeAction(DIcon("close"), tr("Close recording"), SLOT(closeFileSlot())), mTraceFileNotNull); mMenuBuilder->addAction(makeAction(DIcon("delete"), tr("Delete recording"), SLOT(closeDeleteSlot())), mTraceFileNotNull); + mMenuBuilder->addAction(makeShortcutAction(DIcon("browseinexplorer"), tr("Browse in Explorer"), SLOT(browseInExplorerSlot()), "ActionBrowseInExplorer"), mTraceFileNotNull); mMenuBuilder->loadFromConfig(); } @@ -1283,18 +1281,17 @@ void TraceBrowser::openFileSlot() void TraceBrowser::openSlot(const QString & fileName) { - //if(mTraceFile != nullptr) - //{ - // mTraceFile->Close(); - // delete mTraceFile; - //} - //mTraceFile = new TraceFileReader(this); - //connect(mTraceFile, SIGNAL(parseFinished()), this, SLOT(parseFinishedSlot())); - //mFileName = fileName; - //mTraceFile->Open(fileName); GuiOpenTraceFile(fileName.toUtf8().constData()); // Open in Trace Manager } +void TraceBrowser::browseInExplorerSlot() +{ + QStringList arguments; + arguments << QString("/select,"); + arguments << QString(mTraceFile->FileName()); + QProcess::startDetached(QString("%1/explorer.exe").arg(QProcessEnvironment::systemEnvironment().value("windir")), arguments); +} + void TraceBrowser::toggleTraceRecordingSlot() { toggleTraceRecording(this); diff --git a/src/gui/Src/Tracer/TraceBrowser.h b/src/gui/Src/Tracer/TraceBrowser.h index eb121d84fe..d40343ab40 100644 --- a/src/gui/Src/Tracer/TraceBrowser.h +++ b/src/gui/Src/Tracer/TraceBrowser.h @@ -152,6 +152,7 @@ class TraceBrowser : public AbstractTableView public slots: void openFileSlot(); void openSlot(const QString & fileName); + void browseInExplorerSlot(); void toggleTraceRecordingSlot(); void closeFileSlot(); void closeDeleteSlot(); diff --git a/src/gui/Src/Tracer/TraceFileReader.cpp b/src/gui/Src/Tracer/TraceFileReader.cpp index 6849b3cef8..e7503e7005 100644 --- a/src/gui/Src/Tracer/TraceFileReader.cpp +++ b/src/gui/Src/Tracer/TraceFileReader.cpp @@ -160,6 +160,11 @@ const QString & TraceFileReader::ExePath() const return EXEPath; } +QString TraceFileReader::FileName() const +{ + return QDir::toNativeSeparators(traceFile.fileName()); +} + // Return the registers context at a given index REGDUMP TraceFileReader::Registers(unsigned long long index) { diff --git a/src/gui/Src/Tracer/TraceFileReader.h b/src/gui/Src/Tracer/TraceFileReader.h index be4aa3496b..2dd91677a1 100644 --- a/src/gui/Src/Tracer/TraceFileReader.h +++ b/src/gui/Src/Tracer/TraceFileReader.h @@ -41,6 +41,7 @@ class TraceFileReader : public QObject // Get hash of EXE duint HashValue() const; const QString & ExePath() const; + QString FileName() const; void purgeLastPage(); From 5f1868b6985b699642260ccf2ca2b96ad451c41e Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Thu, 11 Apr 2024 00:36:31 +0800 Subject: [PATCH 23/33] Add stack view in trace browser --- src/gui/Src/Tracer/TraceDump.cpp | 1 + src/gui/Src/Tracer/TraceFileReader.cpp | 5 + src/gui/Src/Tracer/TraceStack.cpp | 833 +++++++++++++++++++++++++ src/gui/Src/Tracer/TraceStack.h | 91 +++ src/gui/Src/Tracer/TraceWidget.cpp | 30 +- src/gui/Src/Tracer/TraceWidget.h | 4 +- src/gui/x64dbg.pro | 2 + 7 files changed, 949 insertions(+), 17 deletions(-) create mode 100644 src/gui/Src/Tracer/TraceStack.cpp create mode 100644 src/gui/Src/Tracer/TraceStack.h diff --git a/src/gui/Src/Tracer/TraceDump.cpp b/src/gui/Src/Tracer/TraceDump.cpp index e5ca6edd5a..0ac23166cf 100644 --- a/src/gui/Src/Tracer/TraceDump.cpp +++ b/src/gui/Src/Tracer/TraceDump.cpp @@ -178,6 +178,7 @@ void TraceDump::setupContextMenu() TraceDump::~TraceDump() { + mMemPage = nullptr; // Let the stack view delete it instead! If both views are trying to delete, it will crash. } void TraceDump::mousePressEvent(QMouseEvent* event) diff --git a/src/gui/Src/Tracer/TraceFileReader.cpp b/src/gui/Src/Tracer/TraceFileReader.cpp index ce175c6c5c..3a3ac606b6 100644 --- a/src/gui/Src/Tracer/TraceFileReader.cpp +++ b/src/gui/Src/Tracer/TraceFileReader.cpp @@ -592,6 +592,11 @@ void TraceFileReader::purgeLastPage() error = true; errorMessage = "[TraceFileReader::purgeLastPage] " + QString::fromStdWString(errReason); } + catch(std::bad_alloc &) + { + error = true; + errorMessage = "[TraceFileReader::purgeLastPage] std::bad_alloc"; + } } // Extract memory access information of given index into dump object diff --git a/src/gui/Src/Tracer/TraceStack.cpp b/src/gui/Src/Tracer/TraceStack.cpp new file mode 100644 index 0000000000..6ddb7f0d71 --- /dev/null +++ b/src/gui/Src/Tracer/TraceStack.cpp @@ -0,0 +1,833 @@ +#include "TraceStack.h" +#include "TraceDump.h" +#include "TraceFileReader.h" +#include "TraceFileDump.h" +#include "CPUDump.h" +#include +#include "Configuration.h" +#include "Bridge.h" +#include "CommonActions.h" +#include "HexEditDialog.h" +#include "WordEditDialog.h" +#include "CPUMultiDump.h" +#include "GotoDialog.h" + +TraceStack::TraceStack(Architecture* architecture, TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent) + : mMemoryPage(memoryPage), HexDump(architecture, parent, memoryPage) +{ + setWindowTitle("Stack"); + setDrawDebugOnly(false); + setShowHeader(false); + int charwidth = getCharWidth(); + ColumnDescriptor colDesc; + DataDescriptor dDesc; + + mForceColumn = 1; + + colDesc.isData = true; //void* + colDesc.itemCount = 1; + colDesc.separator = 0; +#ifdef _WIN64 + colDesc.data.itemSize = Qword; + colDesc.data.qwordMode = HexQword; +#else + colDesc.data.itemSize = Dword; + colDesc.data.dwordMode = HexDword; +#endif + appendDescriptor(10 + charwidth * 2 * sizeof(duint), "void*", false, colDesc); + + colDesc.isData = false; //comments + colDesc.itemCount = 0; + colDesc.separator = 0; + dDesc.itemSize = Byte; + dDesc.byteMode = AsciiByte; + colDesc.data = dDesc; + appendDescriptor(2000, tr("Comments"), false, colDesc); + + setupContextMenu(); + + mGoto = 0; + + // Slots + connect(this, SIGNAL(selectionUpdated()), this, SLOT(selectionUpdatedSlot())); + + Initialize(); +} + +void TraceStack::updateColors() +{ + HexDump::updateColors(); + + mBackgroundColor = ConfigColor("StackBackgroundColor"); + mTextColor = ConfigColor("StackTextColor"); + mSelectionColor = ConfigColor("StackSelectionColor"); + //mStackReturnToColor = ConfigColor("StackReturnToColor"); + //mStackSEHChainColor = ConfigColor("StackSEHChainColor"); + //mUserStackFrameColor = ConfigColor("StackFrameColor"); + //mSystemStackFrameColor = ConfigColor("StackFrameSystemColor"); +} + +void TraceStack::updateFonts() +{ + setFont(ConfigFont("Stack")); + invalidateCachedFont(); +} + +void TraceStack::setupContextMenu() +{ + mMenuBuilder = new MenuBuilder(this, [](QMenu*) + { + return DbgIsDebugging(); + }); + mCommonActions = new CommonActions(this, getActionHelperFuncs(), [this]() + { + return rvaToVa(getSelectionStart()); + }); + + //Realign + mMenuBuilder->addAction(makeAction(DIcon("align-stack-pointer"), tr("Align Stack Pointer"), SLOT(realignSlot())), [this](QMenu*) + { + return (mCsp & (sizeof(duint) - 1)) != 0; + }); + + // Modify + //mMenuBuilder->addAction(makeAction(DIcon("modify"), tr("Modify"), SLOT(modifySlot()))); + + auto binaryMenu = new MenuBuilder(this); + + //Binary->Edit + //binaryMenu->addAction(makeShortcutAction(DIcon("binary_edit"), tr("&Edit"), SLOT(binaryEditSlot()), "ActionBinaryEdit")); + + //Binary->Fill + //binaryMenu->addAction(makeShortcutAction(DIcon("binary_fill"), tr("&Fill..."), SLOT(binaryFillSlot()), "ActionBinaryFill")); + + //Binary->Separator + //binaryMenu->addSeparator(); + + //Binary->Copy + binaryMenu->addAction(makeShortcutAction(DIcon("binary_copy"), tr("&Copy"), SLOT(binaryCopySlot()), "ActionBinaryCopy")); + + //Binary->Paste + //binaryMenu->addAction(makeShortcutAction(DIcon("binary_paste"), tr("&Paste"), SLOT(binaryPasteSlot()), "ActionBinaryPaste")); + + //Binary->Paste (Ignore Size) + //binaryMenu->addAction(makeShortcutAction(DIcon("binary_paste_ignoresize"), tr("Paste (&Ignore Size)"), SLOT(binaryPasteIgnoreSizeSlot()), "ActionBinaryPasteIgnoreSize")); + + mMenuBuilder->addMenu(makeMenu(DIcon("binary"), tr("B&inary")), binaryMenu); + + auto copyMenu = new MenuBuilder(this); + copyMenu->addAction(mCopySelection); + copyMenu->addAction(mCopyAddress); + copyMenu->addAction(mCopyRva, [this](QMenu*) + { + return DbgFunctions()->ModBaseFromAddr(rvaToVa(getInitialSelection())) != 0; + }); + + //Copy->DWORD/QWORD + QString ptrName = ArchValue(tr("&DWORD"), tr("&QWORD")); + copyMenu->addAction(makeAction(ptrName, SLOT(copyPtrColumnSlot()))); + + //Copy->Comments + copyMenu->addAction(makeAction(tr("&Comments"), SLOT(copyCommentsColumnSlot()))); + + mMenuBuilder->addMenu(makeMenu(DIcon("copy"), tr("&Copy")), copyMenu); + + //Breakpoint (hardware access) menu + auto hardwareAccessMenu = makeMenu(DIcon("breakpoint_access"), tr("Hardware, Access")); + hardwareAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_byte"), tr("&Byte"), "bphws $, r, 1")); + hardwareAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_word"), tr("&Word"), "bphws $, r, 2")); + hardwareAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_dword"), tr("&Dword"), "bphws $, r, 4")); +#ifdef _WIN64 + hardwareAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_qword"), tr("&Qword"), "bphws $, r, 8")); +#endif //_WIN64 + + //Breakpoint (hardware write) menu + auto hardwareWriteMenu = makeMenu(DIcon("breakpoint_write"), tr("Hardware, Write")); + hardwareWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_byte"), tr("&Byte"), "bphws $, w, 1")); + hardwareWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_word"), tr("&Word"), "bphws $, w, 2")); + hardwareWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_dword"), tr("&Dword"), "bphws $, w, 4")); +#ifdef _WIN64 + hardwareWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_qword"), tr("&Qword"), "bphws $, r, 8")); +#endif //_WIN64 + + //Breakpoint (remove hardware) + auto hardwareRemove = mCommonActions->makeCommandAction(DIcon("breakpoint_remove"), tr("Remove &Hardware"), "bphwc $"); + + //Breakpoint (memory access) menu + auto memoryAccessMenu = makeMenu(DIcon("breakpoint_memory_access"), tr("Memory, Access")); + memoryAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_memory_singleshoot"), tr("&Singleshoot"), "bpm $, 0, a")); + memoryAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_memory_restore_on_hit"), tr("&Restore on hit"), "bpm $, 1, a")); + + //Breakpoint (memory write) menu + auto memoryWriteMenu = makeMenu(DIcon("breakpoint_memory_write"), tr("Memory, Write")); + memoryWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_memory_singleshoot"), tr("&Singleshoot"), "bpm $, 0, w")); + memoryWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_memory_restore_on_hit"), tr("&Restore on hit"), "bpm $, 1, w")); + + //Breakpoint (remove memory) menu + auto memoryRemove = mCommonActions->makeCommandAction(DIcon("breakpoint_remove"), tr("Remove &Memory"), "bpmc $"); + + //Breakpoint menu + auto breakpointMenu = new MenuBuilder(this); + + //Breakpoint menu + breakpointMenu->addBuilder(new MenuBuilder(this, [ = ](QMenu * menu) + { + duint selectedAddr = rvaToVa(getInitialSelection()); + if(DbgGetBpxTypeAt(selectedAddr) & bp_hardware) //hardware breakpoint set + { + menu->addAction(hardwareRemove); + } + else //memory breakpoint not set + { + menu->addMenu(hardwareAccessMenu); + menu->addMenu(hardwareWriteMenu); + } + + menu->addSeparator(); + + if(DbgGetBpxTypeAt(selectedAddr) & bp_memory) //memory breakpoint set + { + menu->addAction(memoryRemove); + } + else //memory breakpoint not set + { + menu->addMenu(memoryAccessMenu); + menu->addMenu(memoryWriteMenu); + } + return true; + })); + mMenuBuilder->addMenu(makeMenu(DIcon("breakpoint"), tr("Brea&kpoint")), breakpointMenu); + + // Restore Selection + //mMenuBuilder->addAction(makeShortcutAction(DIcon("eraser"), tr("&Restore selection"), SLOT(undoSelectionSlot()), "ActionUndoSelection"), [this](QMenu*) + //{ + // dsint start = rvaToVa(getSelectionStart()); + // dsint end = rvaToVa(getSelectionEnd()); + // return DbgFunctions()->PatchInRange(start, end); + //}); + + //Find Pattern + //mMenuBuilder->addAction(makeShortcutAction(DIcon("search-for"), tr("&Find Pattern..."), SLOT(findPattern()), "ActionFindPattern")); + + //Follow CSP + //mMenuBuilder->addAction(makeShortcutAction(DIcon("neworigin"), ArchValue(tr("Follow E&SP"), tr("Follow R&SP")), SLOT(gotoCspSlot()), "ActionGotoOrigin")); + //mMenuBuilder->addAction(makeShortcutAction(DIcon("cbp"), ArchValue(tr("Follow E&BP"), tr("Follow R&BP")), SLOT(gotoCbpSlot()), "ActionGotoCBP"), [](QMenu*) + //{ + // return DbgMemIsValidReadPtr(DbgValFromString("cbp")); + //}); + + auto gotoMenu = new MenuBuilder(this); + + //Go to Expression + gotoMenu->addAction(makeShortcutAction(DIcon("geolocation-goto"), tr("Go to &Expression"), SLOT(gotoExpressionSlot()), "ActionGotoExpression")); + + //Go to Base of Stack Frame + //gotoMenu->addAction(makeShortcutAction(DIcon("neworigin"), tr("Go to Base of Stack Frame"), SLOT(gotoFrameBaseSlot()), "ActionGotoBaseOfStackFrame")); + + //Go to Previous Frame + //gotoMenu->addAction(makeShortcutAction(DIcon("previous"), tr("Go to Previous Stack Frame"), SLOT(gotoPreviousFrameSlot()), "ActionGotoPrevStackFrame")); + + //Go to Next Frame + //gotoMenu->addAction(makeShortcutAction(DIcon("next"), tr("Go to Next Stack Frame"), SLOT(gotoNextFrameSlot()), "ActionGotoNextStackFrame")); + + //Go to Previous + gotoMenu->addAction(makeShortcutAction(DIcon("previous"), tr("Go to Previous"), SLOT(gotoPreviousSlot()), "ActionGotoPrevious"), [this](QMenu*) + { + return mHistory.historyHasPrev(); + }); + + //Go to Next + gotoMenu->addAction(makeShortcutAction(DIcon("next"), tr("Go to Next"), SLOT(gotoNextSlot()), "ActionGotoNext"), [this](QMenu*) + { + return mHistory.historyHasNext(); + }); + + mMenuBuilder->addMenu(makeMenu(DIcon("goto"), tr("&Go to")), gotoMenu); + + //Freeze the stack + //mMenuBuilder->addAction(mFreezeStack = makeShortcutAction(DIcon("freeze"), tr("Freeze the stack"), SLOT(freezeStackSlot()), "ActionFreezeStack")); + //mFreezeStack->setCheckable(true); + + //Follow in Memory Map + mCommonActions->build(mMenuBuilder, CommonActions::ActionMemoryMap | CommonActions::ActionDump | CommonActions::ActionDumpData); + + //Follow in Stack + auto followStackName = ArchValue(tr("Follow DWORD in &Stack"), tr("Follow QWORD in &Stack")); + mFollowStack = makeAction(DIcon("stack"), followStackName, SLOT(followStackSlot())); + mFollowStack->setShortcutContext(Qt::WidgetShortcut); + mFollowStack->setShortcut(QKeySequence("enter")); + mMenuBuilder->addAction(mFollowStack, [this](QMenu*) + { + duint ptr; + if(!DbgMemRead(rvaToVa(getInitialSelection()), (unsigned char*)&ptr, sizeof(ptr))) + return false; + duint stackBegin = mMemPage->getBase(); + duint stackEnd = stackBegin + mMemPage->getSize(); + return ptr >= stackBegin && ptr < stackEnd; + }); + + //Follow in Disassembler + auto disasmIcon = DIcon(ArchValue("processor32", "processor64")); + mFollowDisasm = makeAction(disasmIcon, ArchValue(tr("&Follow DWORD in Disassembler"), tr("&Follow QWORD in Disassembler")), SLOT(followDisasmSlot())); + mFollowDisasm->setShortcutContext(Qt::WidgetShortcut); + mFollowDisasm->setShortcut(QKeySequence("enter")); + mMenuBuilder->addAction(mFollowDisasm, [this](QMenu*) + { + duint ptr; + return DbgMemRead(rvaToVa(getInitialSelection()), (unsigned char*)&ptr, sizeof(ptr)) && DbgMemIsValidReadPtr(ptr); + }); + + //Follow PTR in Dump + auto followDumpName = ArchValue(tr("Follow DWORD in &Dump"), tr("Follow QWORD in &Dump")); + + mCommonActions->build(mMenuBuilder, CommonActions::ActionDumpN | CommonActions::ActionWatch); + mMenuBuilder->addAction(makeAction("Edit columns...", SLOT(editColumnDialog()))); + + //mPluginMenu = new QMenu(this); + //Bridge::getBridge()->emitMenuAddToList(this, mPluginMenu, GUI_STACK_MENU); + + //mMenuBuilder->addSeparator(); + //mMenuBuilder->addBuilder(new MenuBuilder(this, [this](QMenu * menu) + //{ + // DbgMenuPrepare(GUI_STACK_MENU); + // menu->addActions(mPluginMenu->actions()); + // return true; + //})); + + mMenuBuilder->loadFromConfig(); + disconnect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(debugStateChanged(DBGSTATE))); + updateShortcuts(); +} + +//void TraceStack::updateFreezeStackAction() +//{ +// if(bStackFrozen) +// mFreezeStack->setText(tr("Unfreeze the stack")); +// else +// mFreezeStack->setText(tr("Freeze the stack")); +// mFreezeStack->setChecked(bStackFrozen); +//} + +void TraceStack::getColumnRichText(duint col, duint rva, RichTextPainter::List & richText) +{ + // Compute VA + duint va = rvaToVa(rva); + + bool activeStack = (va >= mCsp); //inactive stack + + //STACK_COMMENT comment; + RichTextPainter::CustomRichText_t curData; + curData.underline = false; + curData.flags = RichTextPainter::FlagColor; + curData.textColor = mTextColor; + + if(col && mDescriptor.at(col - 1).isData == true) //paint stack data + { + HexDump::getColumnRichText(col, rva, richText); + if(!activeStack) + { + QColor inactiveColor = ConfigColor("StackInactiveTextColor"); + for(int i = 0; i < int(richText.size()); i++) + { + richText[i].flags = RichTextPainter::FlagColor; + richText[i].textColor = inactiveColor; + } + } + } + else if(col) //TODO: paint stack comments + { + /*if(activeStack) + { + if(*comment.color) + { + if(comment.color[0] == '!') + { + if(strcmp(comment.color, "!sehclr") == 0) + curData.textColor = mStackSEHChainColor; + else if(strcmp(comment.color, "!rtnclr") == 0) + curData.textColor = mStackReturnToColor; + else + curData.textColor = mTextColor; + } + else + curData.textColor = QColor(QString(comment.color)); + } + else*/ + curData.textColor = mTextColor; + /*} + else + curData.textColor = ConfigColor("StackInactiveTextColor");*/ + curData.text = ""; + richText.push_back(curData); + } + else + HexDump::getColumnRichText(col, rva, richText); +} + +QString TraceStack::paintContent(QPainter* painter, duint row, duint col, int x, int y, int w, int h) +{ + // Compute RVA + auto bytePerRowCount = getBytePerRowCount(); + dsint rva = row * bytePerRowCount - mByteOffset; + duint va = rvaToVa(rva); + + bool rowSelected = isSelected(rva); + if(rowSelected) //highlight if selected + painter->fillRect(QRect(x, y, w, h), QBrush(mSelectionColor)); + + if(col == 0) // paint stack address + { + QColor background; + char labelText[MAX_LABEL_SIZE] = ""; + if(DbgGetLabelAt(va, SEG_DEFAULT, labelText)) //label + { + if(va == mCsp) //CSP + { + background = ConfigColor("StackCspBackgroundColor"); + painter->setPen(QPen(ConfigColor("StackCspColor"))); + } + else //no CSP + { + background = ConfigColor("StackLabelBackgroundColor"); + painter->setPen(ConfigColor("StackLabelColor")); + } + } + else //no label + { + if(va == mCsp) //CSP + { + background = ConfigColor("StackCspBackgroundColor"); + painter->setPen(QPen(ConfigColor("StackCspColor"))); + } + else if(rowSelected) //selected normal address + { + background = ConfigColor("StackSelectedAddressBackgroundColor"); + painter->setPen(QPen(ConfigColor("StackSelectedAddressColor"))); //black address (DisassemblySelectedAddressColor) + } + else //normal address + { + background = ConfigColor("StackAddressBackgroundColor"); + painter->setPen(QPen(ConfigColor("StackAddressColor"))); + } + } + if(background.alpha()) + painter->fillRect(QRect(x, y, w, h), QBrush(background)); //fill background when defined + painter->drawText(QRect(x + 4, y, w - 4, h), Qt::AlignVCenter | Qt::AlignLeft, makeAddrText(va)); + return QString(); + } + else // TODO: Print call stack + return HexDump::paintContent(painter, row, col, x, y, w, h); +} + +void TraceStack::contextMenuEvent(QContextMenuEvent* event) +{ + QMenu menu(this); //create context menu + mMenuBuilder->build(&menu); + menu.exec(event->globalPos()); +} + +void TraceStack::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) + auto 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; + + case 1: // value + { + //modifySlot(); + } + break; + + default: + { + duint va = rvaToVa(getInitialSelection()); + STACK_COMMENT comment; + if(DbgStackCommentGet(va, &comment) && strcmp(comment.color, "!rtnclr") == 0) + followDisasmSlot(); + } + break; + } +} + +void TraceStack::wheelEvent(QWheelEvent* event) +{ + if(event->modifiers() == Qt::NoModifier) + AbstractTableView::wheelEvent(event); + else if(event->modifiers() == Qt::ControlModifier) // Zoom + Config()->zoomFont("Stack", event); +} + +void TraceStack::stackDumpAt(duint addr, duint csp) +{ + if(DbgMemIsValidReadPtr(addr)) + mHistory.addVaToHistory(addr); + mCsp = csp; + + // Get the callstack + //DBGCALLSTACK callstack; + //memset(&callstack, 0, sizeof(DBGCALLSTACK)); + //DbgFunctions()->GetCallStack(&callstack); + //mCallstack.resize(callstack.total); + //if(mCallstack.size()) + //{ + // callstack data highest >> lowest + //std::qsort(callstack.entries, callstack.total, sizeof(DBGCALLSTACKENTRY), [](const void* a, const void* b) + //{ + //auto p = (const DBGCALLSTACKENTRY*)a; + //auto q = (const DBGCALLSTACKENTRY*)b; + //if(p->addr < q->addr) + //return -1; + //else + //return 1; + //}); + //for(size_t i = 0; i < mCallstack.size(); i++) + //{ + //mCallstack[i].addr = callstack.entries[i].addr; + //mCallstack[i].party = DbgFunctions()->ModGetParty(callstack.entries[i].to); + //} + //BridgeFree(callstack.entries); + //} + bool isInvisible; + isInvisible = (addr < mMemPage->va(getTableOffsetRva())) || (addr >= mMemPage->va(getTableOffsetRva() + getViewableRowsCount() * getBytePerRowCount())); + + printDumpAt(addr, true, true, isInvisible || addr == csp); +} + +void TraceStack::updateSlot() +{ + if(!DbgIsDebugging()) + return; + // Get the callstack + DBGCALLSTACK callstack; + memset(&callstack, 0, sizeof(DBGCALLSTACK)); + DbgFunctions()->GetCallStack(&callstack); + //mCallstack.resize(callstack.total); + //if(mCallstack.size()) + //{ + // callstack data highest >> lowest + //std::qsort(callstack.entries, callstack.total, sizeof(DBGCALLSTACKENTRY), [](const void* a, const void* b) + //{ + //auto p = (const DBGCALLSTACKENTRY*)a; + //auto q = (const DBGCALLSTACKENTRY*)b; + //if(p->addr < q->addr) + //return -1; + //else + //return 1; + //}); + //for(size_t i = 0; i < mCallstack.size(); i++) + //{ + //mCallstack[i].addr = callstack.entries[i].addr; + //mCallstack[i].party = DbgFunctions()->ModGetParty(callstack.entries[i].to); + //} + //BridgeFree(callstack.entries); + //} +} + +void TraceStack::printDumpAt(duint parVA, bool select, bool repaint, bool updateTableOffset) +{ + // Modified from Hexdump, removed memory page information + // TODO: get memory range from trace instead + const duint wSize = 0x1000; // TODO: Using 4KB pages currently + auto wBase = mMemoryPage->getBase(); + dsint wRVA = parVA - wBase; //calculate rva + if(wRVA < 0 || wRVA >= wSize) + { + wBase = parVA & ~(wSize - 1); + mMemoryPage->setAttributes(wBase, wSize); + wRVA = parVA - wBase; //calculate rva + } + int wBytePerRowCount = getBytePerRowCount(); //get the number of bytes per row + dsint wRowCount; + + // Byte offset used to be aligned on the given RVA + mByteOffset = (int)((dsint)wRVA % (dsint)wBytePerRowCount); + mByteOffset = mByteOffset > 0 ? wBytePerRowCount - mByteOffset : 0; + + // Compute row count + wRowCount = wSize / wBytePerRowCount; + wRowCount += mByteOffset > 0 ? 1 : 0; + + //if(mRvaDisplayEnabled && mMemPage->getBase() != mRvaDisplayPageBase) + // mRvaDisplayEnabled = false; + + setRowCount(wRowCount); //set the number of rows + + if(updateTableOffset) + { + setTableOffset(-1); //make sure the requested address is always first + setTableOffset((wRVA + mByteOffset) / wBytePerRowCount); //change the displayed offset + } + + if(select) + { + setSingleSelection(wRVA); + dsint wEndingAddress = wRVA + getSizeOf(mDescriptor.at(0).data.itemSize) - 1; + expandSelectionUpTo(wEndingAddress); + } + + if(repaint) + reloadData(); +} + +void TraceStack::disasmSelectionChanged(duint parVA) +{ + // When the selected instruction is changed, select the argument that is in the stack. + DISASM_INSTR instr; + if(!DbgIsDebugging() || !DbgMemIsValidReadPtr(parVA)) + return; + DbgDisasmAt(parVA, &instr); + + duint underlineStart = 0; + duint underlineEnd = 0; + + for(int i = 0; i < instr.argcount; i++) + { + const DISASM_ARG & arg = instr.arg[i]; + if(arg.type == arg_memory) + { + if(arg.value >= mMemPage->getBase() && arg.value < mMemPage->getBase() + mMemPage->getSize()) + { + if(Config()->getBool("Gui", "AutoFollowInStack")) + { + //TODO: When the stack is unaligned? + stackDumpAt(arg.value & (~(sizeof(void*) - 1)), mCsp); + } + else + { + BASIC_INSTRUCTION_INFO info; + DbgDisasmFastAt(parVA, &info); + underlineStart = arg.value; + underlineEnd = mUnderlineRangeStartVa + info.memory.size - 1; + } + break; + } + } + } + + if(mUnderlineRangeStartVa != underlineStart || mUnderlineRangeEndVa != underlineEnd) + { + mUnderlineRangeStartVa = underlineStart; + mUnderlineRangeEndVa = underlineEnd; + reloadData(); + } +} + +// TODO +//void TraceStack::gotoCspSlot() +//{ +//DbgCmdExec("sdump csp"); +//} + +//void TraceStack::gotoCbpSlot() +//{ +//DbgCmdExec("sdump cbp"); +//} + +//int TraceStack::getCurrentFrame(const std::vector & mCallstack, duint va) +//{ +//if(mCallstack.size()) +//for(size_t i = 0; i < mCallstack.size() - 1; i++) +//if(va >= mCallstack[i].addr && va < mCallstack[i + 1].addr) +//return int(i); +//return -1; +//} + +//void TraceStack::gotoFrameBaseSlot() +//{ +//int frame = getCurrentFrame(mCallstack, rvaToVa(getInitialSelection())); +//if(frame != -1) +//DbgCmdExec(QString("sdump \"%1\"").arg(ToPtrString(mCallstack[frame].addr))); +//} + +//void TraceStack::gotoNextFrameSlot() +//{ +//int frame = getCurrentFrame(mCallstack, rvaToVa(getInitialSelection())); +//if(frame != -1 && frame + 1 < int(mCallstack.size())) +//DbgCmdExec(QString("sdump \"%1\"").arg(ToPtrString(mCallstack[frame + 1].addr))); +//} + +//void TraceStack::gotoPreviousFrameSlot() +//{ +//int frame = getCurrentFrame(mCallstack, rvaToVa(getInitialSelection())); +//if(frame > 0) +//DbgCmdExec(QString("sdump \"%1\"").arg(ToPtrString(mCallstack[frame - 1].addr))); +//} + +void TraceStack::gotoExpressionSlot() +{ + if(!DbgIsDebugging()) + return; + duint size = 0; + duint base = DbgMemFindBaseAddr(mCsp, &size); + if(!mGoto) + mGoto = new GotoDialog(this); + mGoto->validRangeStart = base; + mGoto->validRangeEnd = base + size; + mGoto->setWindowTitle(tr("Enter expression to follow in Stack...")); + mGoto->setInitialExpression(ToPtrString(rvaToVa(getInitialSelection()))); + if(mGoto->exec() == QDialog::Accepted) + { + duint value = DbgValFromString(mGoto->expressionText.toUtf8().constData()); + DbgCmdExec(QString().sprintf("sdump %p", value)); + } +} + +void TraceStack::selectionGet(SELECTIONDATA* selection) +{ + selection->start = rvaToVa(getSelectionStart()); + selection->end = rvaToVa(getSelectionEnd()); + Bridge::getBridge()->setResult(BridgeResult::SelectionGet, 1); +} + +void TraceStack::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 TraceStack::selectionUpdatedSlot() +{ + duint selectedData; + if(mMemPage->read((byte_t*)&selectedData, getInitialSelection(), sizeof(duint))) + if(DbgMemIsValidReadPtr(selectedData)) //data is a pointer + { + duint stackBegin = mMemPage->getBase(); + duint stackEnd = stackBegin + mMemPage->getSize(); + if(selectedData >= stackBegin && selectedData < stackEnd) //data is a pointer to stack address + { + disconnect(SIGNAL(enterPressedSignal())); + connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followStackSlot())); + mFollowDisasm->setShortcut(QKeySequence("")); + mFollowStack->setShortcut(QKeySequence("enter")); + } + else + { + disconnect(SIGNAL(enterPressedSignal())); + connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followDisasmSlot())); + mFollowStack->setShortcut(QKeySequence("")); + mFollowDisasm->setShortcut(QKeySequence("enter")); + } + } +} + +void TraceStack::followDisasmSlot() +{ + duint selectedData; + if(mMemPage->read((byte_t*)&selectedData, getInitialSelection(), sizeof(duint))) + if(DbgMemIsValidReadPtr(selectedData)) //data is a pointer + { + QString addrText = ToPtrString(selectedData); + DbgCmdExec(QString("disasm " + addrText)); + } +} + +void TraceStack::followStackSlot() +{ + duint selectedData; + if(mMemPage->read((byte_t*)&selectedData, getInitialSelection(), sizeof(duint))) + if(DbgMemIsValidReadPtr(selectedData)) //data is a pointer + { + QString addrText = ToPtrString(selectedData); + DbgCmdExec(QString("sdump " + addrText)); + } +} + +void TraceStack::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 TraceStack::realignSlot() +{ +#ifdef _WIN64 + mCsp &= ~0x7; +#else //x86 + mCsp &= ~0x3; +#endif //_WIN64 + DbgValToString("csp", mCsp); + GuiUpdateAllViews(); +} + +void TraceStack::copyPtrColumnSlot() +{ + const duint wordSize = sizeof(duint); + dsint selStart = getSelectionStart(); + dsint selLen = getSelectionEnd() - selStart + 1; + duint wordCount = selLen / wordSize; + + duint* data = new duint[wordCount]; + mMemPage->read((byte_t*)data, selStart, wordCount * wordSize); + + QString clipboard; + for(duint i = 0; i < wordCount; i++) + { + if(i > 0) + clipboard += "\r\n"; + clipboard += ToPtrString(data[i]); + } + delete [] data; + + Bridge::CopyToClipboard(clipboard); +} + +void TraceStack::copyCommentsColumnSlot() +{ + int commentsColumn = 2; + const duint wordSize = sizeof(duint); + dsint selStart = getSelectionStart(); + dsint selLen = getSelectionEnd() - selStart + 1; + + QString clipboard; + for(dsint i = 0; i < selLen; i += wordSize) + { + RichTextPainter::List richText; + getColumnRichText(commentsColumn, selStart + i, richText); + QString colText; + for(auto & r : richText) + colText += r.text; + + if(i > 0) + clipboard += "\r\n"; + clipboard += colText; + } + + Bridge::CopyToClipboard(clipboard); +} diff --git a/src/gui/Src/Tracer/TraceStack.h b/src/gui/Src/Tracer/TraceStack.h new file mode 100644 index 0000000000..e674875809 --- /dev/null +++ b/src/gui/Src/Tracer/TraceStack.h @@ -0,0 +1,91 @@ +#pragma once + +#include "HexDump.h" + +//forward declaration +class CPUMultiDump; +class GotoDialog; +class CommonActions; +class TraceBrowser; +class TraceFileDumpMemoryPage; + +class TraceStack : public HexDump +{ + Q_OBJECT +public: + explicit TraceStack(Architecture* architecture, TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent = nullptr); + + // Configuration + void updateColors() override; + void updateFonts() override; + + void getColumnRichText(duint col, duint rva, RichTextPainter::List & richText) override; + QString paintContent(QPainter* painter, duint row, duint col, int x, int y, int w, int h) override; + void contextMenuEvent(QContextMenuEvent* event) override; + void mouseDoubleClickEvent(QMouseEvent* event) override; + void wheelEvent(QWheelEvent* event) override; + void setupContextMenu(); + //void updateFreezeStackAction(); + void printDumpAt(duint parVA, bool select, bool repaint, bool updateTableOffset) override; + +signals: + void displayReferencesWidget(); + +public slots: + void stackDumpAt(duint addr, duint csp); + //void gotoCspSlot(); + //5void gotoCbpSlot(); + void gotoExpressionSlot(); + //void gotoPreviousFrameSlot(); + //void gotoNextFrameSlot(); + //void gotoFrameBaseSlot(); + void selectionGet(SELECTIONDATA* selection); + void selectionSet(const SELECTIONDATA* selection); + void selectionUpdatedSlot(); + void followDisasmSlot(); + void followStackSlot(); + //void binaryEditSlot(); + //void binaryFillSlot(); + void binaryCopySlot(); + //void binaryPasteSlot(); + //void findPattern(); + //void binaryPasteIgnoreSizeSlot(); + //void undoSelectionSlot(); + //void modifySlot(); + void realignSlot(); + //void freezeStackSlot(); + //void dbgStateChangedSlot(DBGSTATE state); + void disasmSelectionChanged(duint parVA); + void updateSlot(); + void copyPtrColumnSlot(); + void copyCommentsColumnSlot(); + +private: + TraceFileDumpMemoryPage* mMemoryPage; + + duint mCsp = 0; + bool bStackFrozen = false; + + QAction* mFreezeStack; + QAction* mFollowStack; + QAction* mFollowDisasm; + //QMenu* mPluginMenu; + + GotoDialog* mGoto; + //CPUMultiDump* mMultiDump; + //QColor mUserStackFrameColor; + //QColor mSystemStackFrameColor; + //QColor mStackReturnToColor; + //QColor mStackSEHChainColor; + //struct CPUCallStack + //{ + // duint addr; + // int party; + //}; + + MenuBuilder* mMenuBuilder; + CommonActions* mCommonActions; + + //std::vector mCallstack; + //static int CPUStack::getCurrentFrame(const std::vector & mCallstack, duint va); +}; diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index 09f0bed7f7..9c3a656b51 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -3,6 +3,7 @@ #include "TraceBrowser.h" #include "TraceInfoBox.h" #include "TraceDump.h" +#include "TraceStack.h" #include "TraceFileReader.h" #include "TraceRegisters.h" #include "StdTable.h" @@ -17,17 +18,18 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q mTraceFile = new TraceFileReader(this); mTraceFile->Open(fileName); mTraceBrowser = new TraceBrowser(mTraceFile, this); - mOverview = new StdTable(this); mInfo = new TraceInfoBox(this); if(!Config()->getBool("Gui", "DisableTraceDump")) { mMemoryPage = new TraceFileDumpMemoryPage(mTraceFile->getDump(), this); mDump = new TraceDump(architecture, mTraceBrowser, mMemoryPage, this); + mStack = new TraceStack(architecture, mTraceBrowser, mMemoryPage, this); } else { mMemoryPage = nullptr; mDump = nullptr; + mStack = nullptr; } mGeneralRegs = new TraceRegisters(this); //disasm @@ -62,30 +64,25 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q int height = mInfo->getHeight(); ui->mTopLeftLowerFrame->setMinimumHeight(height + 2); - //dump if(mDump) + { + //dump ui->mBotLeftFrameLayout->addWidget(mDump); - //overview - ui->mBotRightFrameLayout->addWidget(mOverview); - - // TODO: set up overview - mOverview->addColumnAt(0, "", true); - mOverview->setShowHeader(false); - mOverview->setRowCount(4); - mOverview->setCellContent(0, 0, "hello"); - mOverview->setCellContent(1, 0, "world"); - mOverview->setCellContent(2, 0, "00000000"); - mOverview->setCellContent(3, 0, "TODO: Draw call stack here"); - mOverview->hide(); + //stack + ui->mBotRightFrameLayout->addWidget(mStack); + } + ui->mTopHSplitter->setSizes(QList({1000, 1})); ui->mTopLeftVSplitter->setSizes(QList({1000, 1})); mTraceBrowser->setAccessibleName(tr("Disassembly")); - mOverview->setAccessibleName(tr("Stack")); upperScrollArea->setAccessibleName(tr("Registers")); if(mDump) + { mDump->setAccessibleName(tr("Dump")); + mStack->setAccessibleName(tr("Stack")); + } mInfo->setAccessibleName(tr("InfoBox")); } @@ -116,6 +113,7 @@ void TraceWidget::traceSelectionChanged(unsigned long long selection) mTraceFile->buildDumpTo(selection); // TODO: sometimes this can be slow // TODO: Is it a good idea to build dump index just when opening the file? mMemoryPage->setSelectedIndex(selection); mDump->reloadData(); + mStack->reloadData(); } } else @@ -163,6 +161,8 @@ void TraceWidget::parseFinishedSlot() initialAddress = mTraceFile->Registers(0).regcontext.cip; } mDump->printDumpAt(initialAddress, false, true, true); + // Setting the initial address of stack view + mStack->printDumpAt(mTraceFile->Registers(0).regcontext.csp, false, true, true); } mGeneralRegs->setActive(true); } diff --git a/src/gui/Src/Tracer/TraceWidget.h b/src/gui/Src/Tracer/TraceWidget.h index 2782577f6d..9dcedc171d 100644 --- a/src/gui/Src/Tracer/TraceWidget.h +++ b/src/gui/Src/Tracer/TraceWidget.h @@ -11,8 +11,8 @@ class TraceFileReader; class TraceFileDumpMemoryPage; class TraceInfoBox; class TraceDump; +class TraceStack; class TraceFileReader; -class StdTable; namespace Ui { @@ -42,7 +42,7 @@ protected slots: TraceDump* mDump; TraceRegisters* mGeneralRegs; TraceFileDumpMemoryPage* mMemoryPage; - StdTable* mOverview; + TraceStack* mStack; private: Ui::TraceWidget* ui; diff --git a/src/gui/x64dbg.pro b/src/gui/x64dbg.pro index 51d9f8c248..590cb61f0c 100644 --- a/src/gui/x64dbg.pro +++ b/src/gui/x64dbg.pro @@ -85,6 +85,7 @@ SOURCES += \ Src/Tracer/TraceInfoBox.cpp \ Src/Tracer/TraceManager.cpp \ Src/Tracer/TraceRegisters.cpp \ + Src/Tracer/TraceStack.cpp \ Src/Tracer/TraceWidget.cpp \ Src/Utils/CommonActions.cpp \ Src/main.cpp \ @@ -209,6 +210,7 @@ HEADERS += \ Src/Tracer/TraceInfoBox.h \ Src/Tracer/TraceManager.h \ Src/Tracer/TraceRegisters.h \ + Src/Tracer/TraceStack.h \ Src/Tracer/TraceWidget.h \ Src/Utils/CommonActions.h \ Src/main.h \ From d0bd09494a8316d2d957aa8ddb1d66c2360b74ff Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Fri, 12 Apr 2024 16:16:03 +0800 Subject: [PATCH 24/33] Tidy up code of trace stack --- src/gui/Src/Tracer/TraceStack.cpp | 296 ++++++---------------------- src/gui/Src/Tracer/TraceStack.h | 23 +-- src/gui/Src/Utils/Configuration.cpp | 1 + 3 files changed, 61 insertions(+), 259 deletions(-) diff --git a/src/gui/Src/Tracer/TraceStack.cpp b/src/gui/Src/Tracer/TraceStack.cpp index 6ddb7f0d71..dff466114b 100644 --- a/src/gui/Src/Tracer/TraceStack.cpp +++ b/src/gui/Src/Tracer/TraceStack.cpp @@ -2,6 +2,7 @@ #include "TraceDump.h" #include "TraceFileReader.h" #include "TraceFileDump.h" +#include "TraceBrowser.h" #include "CPUDump.h" #include #include "Configuration.h" @@ -13,7 +14,7 @@ #include "GotoDialog.h" TraceStack::TraceStack(Architecture* architecture, TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent) - : mMemoryPage(memoryPage), HexDump(architecture, parent, memoryPage) + : mMemoryPage(memoryPage), mDisas(disas), HexDump(architecture, parent, memoryPage) { setWindowTitle("Stack"); setDrawDebugOnly(false); @@ -49,7 +50,7 @@ TraceStack::TraceStack(Architecture* architecture, TraceBrowser* disas, TraceFil mGoto = 0; // Slots - connect(this, SIGNAL(selectionUpdated()), this, SLOT(selectionUpdatedSlot())); + //connect(this, SIGNAL(selectionUpdated()), this, SLOT(selectionUpdatedSlot())); Initialize(); } @@ -75,44 +76,20 @@ void TraceStack::updateFonts() void TraceStack::setupContextMenu() { - mMenuBuilder = new MenuBuilder(this, [](QMenu*) + mMenuBuilder = new MenuBuilder(this, [this](QMenu*) { - return DbgIsDebugging(); + return mMemoryPage->isAvailable(); }); mCommonActions = new CommonActions(this, getActionHelperFuncs(), [this]() { return rvaToVa(getSelectionStart()); }); - //Realign - mMenuBuilder->addAction(makeAction(DIcon("align-stack-pointer"), tr("Align Stack Pointer"), SLOT(realignSlot())), [this](QMenu*) - { - return (mCsp & (sizeof(duint) - 1)) != 0; - }); - - // Modify - //mMenuBuilder->addAction(makeAction(DIcon("modify"), tr("Modify"), SLOT(modifySlot()))); - auto binaryMenu = new MenuBuilder(this); - //Binary->Edit - //binaryMenu->addAction(makeShortcutAction(DIcon("binary_edit"), tr("&Edit"), SLOT(binaryEditSlot()), "ActionBinaryEdit")); - - //Binary->Fill - //binaryMenu->addAction(makeShortcutAction(DIcon("binary_fill"), tr("&Fill..."), SLOT(binaryFillSlot()), "ActionBinaryFill")); - - //Binary->Separator - //binaryMenu->addSeparator(); - //Binary->Copy binaryMenu->addAction(makeShortcutAction(DIcon("binary_copy"), tr("&Copy"), SLOT(binaryCopySlot()), "ActionBinaryCopy")); - //Binary->Paste - //binaryMenu->addAction(makeShortcutAction(DIcon("binary_paste"), tr("&Paste"), SLOT(binaryPasteSlot()), "ActionBinaryPaste")); - - //Binary->Paste (Ignore Size) - //binaryMenu->addAction(makeShortcutAction(DIcon("binary_paste_ignoresize"), tr("Paste (&Ignore Size)"), SLOT(binaryPasteIgnoreSizeSlot()), "ActionBinaryPasteIgnoreSize")); - mMenuBuilder->addMenu(makeMenu(DIcon("binary"), tr("B&inary")), binaryMenu); auto copyMenu = new MenuBuilder(this); @@ -132,104 +109,17 @@ void TraceStack::setupContextMenu() mMenuBuilder->addMenu(makeMenu(DIcon("copy"), tr("&Copy")), copyMenu); - //Breakpoint (hardware access) menu - auto hardwareAccessMenu = makeMenu(DIcon("breakpoint_access"), tr("Hardware, Access")); - hardwareAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_byte"), tr("&Byte"), "bphws $, r, 1")); - hardwareAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_word"), tr("&Word"), "bphws $, r, 2")); - hardwareAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_dword"), tr("&Dword"), "bphws $, r, 4")); -#ifdef _WIN64 - hardwareAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_qword"), tr("&Qword"), "bphws $, r, 8")); -#endif //_WIN64 - - //Breakpoint (hardware write) menu - auto hardwareWriteMenu = makeMenu(DIcon("breakpoint_write"), tr("Hardware, Write")); - hardwareWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_byte"), tr("&Byte"), "bphws $, w, 1")); - hardwareWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_word"), tr("&Word"), "bphws $, w, 2")); - hardwareWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_dword"), tr("&Dword"), "bphws $, w, 4")); -#ifdef _WIN64 - hardwareWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_qword"), tr("&Qword"), "bphws $, r, 8")); -#endif //_WIN64 - - //Breakpoint (remove hardware) - auto hardwareRemove = mCommonActions->makeCommandAction(DIcon("breakpoint_remove"), tr("Remove &Hardware"), "bphwc $"); - - //Breakpoint (memory access) menu - auto memoryAccessMenu = makeMenu(DIcon("breakpoint_memory_access"), tr("Memory, Access")); - memoryAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_memory_singleshoot"), tr("&Singleshoot"), "bpm $, 0, a")); - memoryAccessMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_memory_restore_on_hit"), tr("&Restore on hit"), "bpm $, 1, a")); - - //Breakpoint (memory write) menu - auto memoryWriteMenu = makeMenu(DIcon("breakpoint_memory_write"), tr("Memory, Write")); - memoryWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_memory_singleshoot"), tr("&Singleshoot"), "bpm $, 0, w")); - memoryWriteMenu->addAction(mCommonActions->makeCommandAction(DIcon("breakpoint_memory_restore_on_hit"), tr("&Restore on hit"), "bpm $, 1, w")); - - //Breakpoint (remove memory) menu - auto memoryRemove = mCommonActions->makeCommandAction(DIcon("breakpoint_remove"), tr("Remove &Memory"), "bpmc $"); - - //Breakpoint menu - auto breakpointMenu = new MenuBuilder(this); - - //Breakpoint menu - breakpointMenu->addBuilder(new MenuBuilder(this, [ = ](QMenu * menu) - { - duint selectedAddr = rvaToVa(getInitialSelection()); - if(DbgGetBpxTypeAt(selectedAddr) & bp_hardware) //hardware breakpoint set - { - menu->addAction(hardwareRemove); - } - else //memory breakpoint not set - { - menu->addMenu(hardwareAccessMenu); - menu->addMenu(hardwareWriteMenu); - } - - menu->addSeparator(); - - if(DbgGetBpxTypeAt(selectedAddr) & bp_memory) //memory breakpoint set - { - menu->addAction(memoryRemove); - } - else //memory breakpoint not set - { - menu->addMenu(memoryAccessMenu); - menu->addMenu(memoryWriteMenu); - } - return true; - })); - mMenuBuilder->addMenu(makeMenu(DIcon("breakpoint"), tr("Brea&kpoint")), breakpointMenu); - - // Restore Selection - //mMenuBuilder->addAction(makeShortcutAction(DIcon("eraser"), tr("&Restore selection"), SLOT(undoSelectionSlot()), "ActionUndoSelection"), [this](QMenu*) - //{ - // dsint start = rvaToVa(getSelectionStart()); - // dsint end = rvaToVa(getSelectionEnd()); - // return DbgFunctions()->PatchInRange(start, end); - //}); - - //Find Pattern - //mMenuBuilder->addAction(makeShortcutAction(DIcon("search-for"), tr("&Find Pattern..."), SLOT(findPattern()), "ActionFindPattern")); + //TODO: Find Pattern //Follow CSP - //mMenuBuilder->addAction(makeShortcutAction(DIcon("neworigin"), ArchValue(tr("Follow E&SP"), tr("Follow R&SP")), SLOT(gotoCspSlot()), "ActionGotoOrigin")); - //mMenuBuilder->addAction(makeShortcutAction(DIcon("cbp"), ArchValue(tr("Follow E&BP"), tr("Follow R&BP")), SLOT(gotoCbpSlot()), "ActionGotoCBP"), [](QMenu*) - //{ - // return DbgMemIsValidReadPtr(DbgValFromString("cbp")); - //}); + mMenuBuilder->addAction(makeShortcutAction(DIcon("neworigin"), ArchValue(tr("Follow E&SP"), tr("Follow R&SP")), SLOT(gotoCspSlot()), "ActionGotoOrigin")); + mMenuBuilder->addAction(makeShortcutAction(DIcon("cbp"), ArchValue(tr("Follow E&BP"), tr("Follow R&BP")), SLOT(gotoCbpSlot()), "ActionGotoCBP")); auto gotoMenu = new MenuBuilder(this); //Go to Expression gotoMenu->addAction(makeShortcutAction(DIcon("geolocation-goto"), tr("Go to &Expression"), SLOT(gotoExpressionSlot()), "ActionGotoExpression")); - //Go to Base of Stack Frame - //gotoMenu->addAction(makeShortcutAction(DIcon("neworigin"), tr("Go to Base of Stack Frame"), SLOT(gotoFrameBaseSlot()), "ActionGotoBaseOfStackFrame")); - - //Go to Previous Frame - //gotoMenu->addAction(makeShortcutAction(DIcon("previous"), tr("Go to Previous Stack Frame"), SLOT(gotoPreviousFrameSlot()), "ActionGotoPrevStackFrame")); - - //Go to Next Frame - //gotoMenu->addAction(makeShortcutAction(DIcon("next"), tr("Go to Next Stack Frame"), SLOT(gotoNextFrameSlot()), "ActionGotoNextStackFrame")); - //Go to Previous gotoMenu->addAction(makeShortcutAction(DIcon("previous"), tr("Go to Previous"), SLOT(gotoPreviousSlot()), "ActionGotoPrevious"), [this](QMenu*) { @@ -277,23 +167,8 @@ void TraceStack::setupContextMenu() return DbgMemRead(rvaToVa(getInitialSelection()), (unsigned char*)&ptr, sizeof(ptr)) && DbgMemIsValidReadPtr(ptr); }); - //Follow PTR in Dump - auto followDumpName = ArchValue(tr("Follow DWORD in &Dump"), tr("Follow QWORD in &Dump")); - - mCommonActions->build(mMenuBuilder, CommonActions::ActionDumpN | CommonActions::ActionWatch); mMenuBuilder->addAction(makeAction("Edit columns...", SLOT(editColumnDialog()))); - //mPluginMenu = new QMenu(this); - //Bridge::getBridge()->emitMenuAddToList(this, mPluginMenu, GUI_STACK_MENU); - - //mMenuBuilder->addSeparator(); - //mMenuBuilder->addBuilder(new MenuBuilder(this, [this](QMenu * menu) - //{ - // DbgMenuPrepare(GUI_STACK_MENU); - // menu->addActions(mPluginMenu->actions()); - // return true; - //})); - mMenuBuilder->loadFromConfig(); disconnect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(debugStateChanged(DBGSTATE))); updateShortcuts(); @@ -364,6 +239,12 @@ void TraceStack::getColumnRichText(duint col, duint rva, RichTextPainter::List & HexDump::getColumnRichText(col, rva, richText); } +void TraceStack::reloadData() +{ + mCsp = mDisas->getTraceFile()->Registers(mDisas->getInitialSelection()).regcontext.csp; + HexDump::reloadData(); +} + QString TraceStack::paintContent(QPainter* painter, duint row, duint col, int x, int y, int w, int h) { // Compute RVA @@ -634,112 +515,57 @@ void TraceStack::disasmSelectionChanged(duint parVA) } // TODO -//void TraceStack::gotoCspSlot() -//{ -//DbgCmdExec("sdump csp"); -//} - -//void TraceStack::gotoCbpSlot() -//{ -//DbgCmdExec("sdump cbp"); -//} - -//int TraceStack::getCurrentFrame(const std::vector & mCallstack, duint va) -//{ -//if(mCallstack.size()) -//for(size_t i = 0; i < mCallstack.size() - 1; i++) -//if(va >= mCallstack[i].addr && va < mCallstack[i + 1].addr) -//return int(i); -//return -1; -//} - -//void TraceStack::gotoFrameBaseSlot() -//{ -//int frame = getCurrentFrame(mCallstack, rvaToVa(getInitialSelection())); -//if(frame != -1) -//DbgCmdExec(QString("sdump \"%1\"").arg(ToPtrString(mCallstack[frame].addr))); -//} - -//void TraceStack::gotoNextFrameSlot() -//{ -//int frame = getCurrentFrame(mCallstack, rvaToVa(getInitialSelection())); -//if(frame != -1 && frame + 1 < int(mCallstack.size())) -//DbgCmdExec(QString("sdump \"%1\"").arg(ToPtrString(mCallstack[frame + 1].addr))); -//} +void TraceStack::gotoCspSlot() +{ + if(getInitialSelection() != mCsp) + stackDumpAt(mCsp, mCsp); +} -//void TraceStack::gotoPreviousFrameSlot() -//{ -//int frame = getCurrentFrame(mCallstack, rvaToVa(getInitialSelection())); -//if(frame > 0) -//DbgCmdExec(QString("sdump \"%1\"").arg(ToPtrString(mCallstack[frame - 1].addr))); -//} +void TraceStack::gotoCbpSlot() +{ + stackDumpAt(mDisas->getTraceFile()->Registers(mDisas->getInitialSelection()).regcontext.cbp, mCsp); +} void TraceStack::gotoExpressionSlot() { - if(!DbgIsDebugging()) + if(!mMemoryPage->isAvailable()) return; - duint size = 0; - duint base = DbgMemFindBaseAddr(mCsp, &size); if(!mGoto) - mGoto = new GotoDialog(this); - mGoto->validRangeStart = base; - mGoto->validRangeEnd = base + size; + mGoto = new GotoDialog(this, false, true, true); + //TODO: Address validation doesn't work for now mGoto->setWindowTitle(tr("Enter expression to follow in Stack...")); mGoto->setInitialExpression(ToPtrString(rvaToVa(getInitialSelection()))); if(mGoto->exec() == QDialog::Accepted) { duint value = DbgValFromString(mGoto->expressionText.toUtf8().constData()); - DbgCmdExec(QString().sprintf("sdump %p", value)); + stackDumpAt(value, mCsp); } } -void TraceStack::selectionGet(SELECTIONDATA* selection) -{ - selection->start = rvaToVa(getSelectionStart()); - selection->end = rvaToVa(getSelectionEnd()); - Bridge::getBridge()->setResult(BridgeResult::SelectionGet, 1); -} - -void TraceStack::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 TraceStack::selectionUpdatedSlot() -{ - duint selectedData; - if(mMemPage->read((byte_t*)&selectedData, getInitialSelection(), sizeof(duint))) - if(DbgMemIsValidReadPtr(selectedData)) //data is a pointer - { - duint stackBegin = mMemPage->getBase(); - duint stackEnd = stackBegin + mMemPage->getSize(); - if(selectedData >= stackBegin && selectedData < stackEnd) //data is a pointer to stack address - { - disconnect(SIGNAL(enterPressedSignal())); - connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followStackSlot())); - mFollowDisasm->setShortcut(QKeySequence("")); - mFollowStack->setShortcut(QKeySequence("enter")); - } - else - { - disconnect(SIGNAL(enterPressedSignal())); - connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followDisasmSlot())); - mFollowStack->setShortcut(QKeySequence("")); - mFollowDisasm->setShortcut(QKeySequence("enter")); - } - } -} +//void TraceStack::selectionUpdatedSlot() +//{ +// duint selectedData; +// if(mMemPage->read((byte_t*)&selectedData, getInitialSelection(), sizeof(duint))) +// if(DbgMemIsValidReadPtr(selectedData)) //data is a pointer +// { +// duint stackBegin = mMemPage->getBase(); +// duint stackEnd = stackBegin + mMemPage->getSize(); +// if(selectedData >= stackBegin && selectedData < stackEnd) //data is a pointer to stack address +// { +// disconnect(SIGNAL(enterPressedSignal())); +// connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followStackSlot())); +// mFollowDisasm->setShortcut(QKeySequence("")); +// mFollowStack->setShortcut(QKeySequence("enter")); +// } +// else +// { +// disconnect(SIGNAL(enterPressedSignal())); +// connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followDisasmSlot())); +// mFollowStack->setShortcut(QKeySequence("")); +// mFollowDisasm->setShortcut(QKeySequence("enter")); +// } +// } +//} void TraceStack::followDisasmSlot() { @@ -756,11 +582,10 @@ void TraceStack::followStackSlot() { duint selectedData; if(mMemPage->read((byte_t*)&selectedData, getInitialSelection(), sizeof(duint))) - if(DbgMemIsValidReadPtr(selectedData)) //data is a pointer - { - QString addrText = ToPtrString(selectedData); - DbgCmdExec(QString("sdump " + addrText)); - } + //if(DbgMemIsValidReadPtr(selectedData)) //data is a pointer + //{ + stackDumpAt(selectedData, mCsp); + //} } void TraceStack::binaryCopySlot() @@ -775,17 +600,6 @@ void TraceStack::binaryCopySlot() Bridge::CopyToClipboard(hexEdit.mHexEdit->pattern(true)); } -void TraceStack::realignSlot() -{ -#ifdef _WIN64 - mCsp &= ~0x7; -#else //x86 - mCsp &= ~0x3; -#endif //_WIN64 - DbgValToString("csp", mCsp); - GuiUpdateAllViews(); -} - void TraceStack::copyPtrColumnSlot() { const duint wordSize = sizeof(duint); diff --git a/src/gui/Src/Tracer/TraceStack.h b/src/gui/Src/Tracer/TraceStack.h index e674875809..a3daa18fe7 100644 --- a/src/gui/Src/Tracer/TraceStack.h +++ b/src/gui/Src/Tracer/TraceStack.h @@ -27,34 +27,21 @@ class TraceStack : public HexDump void setupContextMenu(); //void updateFreezeStackAction(); void printDumpAt(duint parVA, bool select, bool repaint, bool updateTableOffset) override; + void reloadData() override; signals: void displayReferencesWidget(); public slots: void stackDumpAt(duint addr, duint csp); - //void gotoCspSlot(); - //5void gotoCbpSlot(); + void gotoCspSlot(); + void gotoCbpSlot(); void gotoExpressionSlot(); - //void gotoPreviousFrameSlot(); - //void gotoNextFrameSlot(); - //void gotoFrameBaseSlot(); - void selectionGet(SELECTIONDATA* selection); - void selectionSet(const SELECTIONDATA* selection); - void selectionUpdatedSlot(); + //void selectionUpdatedSlot(); void followDisasmSlot(); void followStackSlot(); - //void binaryEditSlot(); - //void binaryFillSlot(); void binaryCopySlot(); - //void binaryPasteSlot(); - //void findPattern(); - //void binaryPasteIgnoreSizeSlot(); - //void undoSelectionSlot(); - //void modifySlot(); - void realignSlot(); //void freezeStackSlot(); - //void dbgStateChangedSlot(DBGSTATE state); void disasmSelectionChanged(duint parVA); void updateSlot(); void copyPtrColumnSlot(); @@ -62,6 +49,7 @@ public slots: private: TraceFileDumpMemoryPage* mMemoryPage; + TraceBrowser* mDisas; duint mCsp = 0; bool bStackFrozen = false; @@ -69,7 +57,6 @@ public slots: QAction* mFreezeStack; QAction* mFollowStack; QAction* mFollowDisasm; - //QMenu* mPluginMenu; GotoDialog* mGoto; //CPUMultiDump* mMultiDump; diff --git a/src/gui/Src/Utils/Configuration.cpp b/src/gui/Src/Utils/Configuration.cpp index 549888a739..25e8b2f504 100644 --- a/src/gui/Src/Utils/Configuration.cpp +++ b/src/gui/Src/Utils/Configuration.cpp @@ -315,6 +315,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false) insertMenuBuilderBools(&guiBool, "View", 50); //Main Menu : View insertMenuBuilderBools(&guiBool, "TraceBrowser", 50); //TraceBrowser insertMenuBuilderBools(&guiBool, "TraceDump", 50); //Trace Dump + insertMenuBuilderBools(&guiBool, "TraceStack", 50); //Trace Stack defaultBools.insert("Gui", guiBool); QMap guiUint; From a436a4bcc15723e343feca815dfb075b11640fec Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Sat, 20 Apr 2024 13:47:58 +0800 Subject: [PATCH 25/33] Add xref dialog to trace dump --- src/gui/Src/Gui/XrefBrowseDialog.h | 2 +- src/gui/Src/Tracer/TraceDump.cpp | 34 ++-- src/gui/Src/Tracer/TraceDump.h | 9 +- src/gui/Src/Tracer/TraceStack.cpp | 35 ++-- src/gui/Src/Tracer/TraceStack.h | 2 + src/gui/Src/Tracer/TraceWidget.cpp | 16 ++ src/gui/Src/Tracer/TraceWidget.h | 3 + src/gui/Src/Tracer/TraceXrefBrowseDialog.cpp | 160 +++++++++++++++++++ src/gui/Src/Tracer/TraceXrefBrowseDialog.h | 55 +++++++ src/gui/Src/Utils/Configuration.cpp | 1 + src/gui/x64dbg.pro | 2 + 11 files changed, 287 insertions(+), 32 deletions(-) create mode 100644 src/gui/Src/Tracer/TraceXrefBrowseDialog.cpp create mode 100644 src/gui/Src/Tracer/TraceXrefBrowseDialog.h diff --git a/src/gui/Src/Gui/XrefBrowseDialog.h b/src/gui/Src/Gui/XrefBrowseDialog.h index c0b8ab520c..2d7f6ff9a2 100644 --- a/src/gui/Src/Gui/XrefBrowseDialog.h +++ b/src/gui/Src/Gui/XrefBrowseDialog.h @@ -53,7 +53,7 @@ private slots: void changeAddress(duint address); void setupContextMenu(); - QString GetFunctionSymbol(duint addr); + static QString GetFunctionSymbol(duint addr); XREF_INFO mXrefInfo; duint mAddress; diff --git a/src/gui/Src/Tracer/TraceDump.cpp b/src/gui/Src/Tracer/TraceDump.cpp index 0ac23166cf..8635e6011b 100644 --- a/src/gui/Src/Tracer/TraceDump.cpp +++ b/src/gui/Src/Tracer/TraceDump.cpp @@ -17,7 +17,7 @@ TraceDump::TraceDump(Architecture* architecture, TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent) : mMemoryPage(memoryPage), HexDump(architecture, parent, memoryPage) { - //mDisas = disas; //TODO: unused + mDisas = disas; setDrawDebugOnly(false); //mMultiDump = multiDump; @@ -92,11 +92,11 @@ void TraceDump::setupContextMenu() 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("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(); @@ -106,6 +106,7 @@ void TraceDump::setupContextMenu() return mHistory.historyHasNext(); }); mMenuBuilder->addMenu(makeMenu(DIcon("goto"), tr("&Go to")), wGotoMenu); + mMenuBuilder->addAction(makeShortcutAction(DIcon("xrefs"), tr("xrefs..."), SLOT(gotoXrefSlot()), "ActionXrefs")); mMenuBuilder->addSeparator(); MenuBuilder* wHexMenu = new MenuBuilder(this); @@ -393,16 +394,21 @@ void TraceDump::gotoExpressionSlot() //... //} -void TraceDump::gotoStartSlot() -{ - duint dest = mMemPage->getBase(); - this->printDumpAt(dest, true, true, true); -} +//void TraceDump::gotoStartSlot() +//{ +// duint dest = mMemPage->getBase(); +// this->printDumpAt(dest, true, true, true); +//} + +//void TraceDump::gotoEndSlot() +//{ +// duint dest = mMemPage->getBase() + mMemPage->getSize() - (getViewableRowsCount() * getBytePerRowCount()); +// this->printDumpAt(dest, true, true, true); +//} -void TraceDump::gotoEndSlot() +void TraceDump::gotoXrefSlot() { - duint dest = mMemPage->getBase() + mMemPage->getSize() - (getViewableRowsCount() * getBytePerRowCount()); - this->printDumpAt(dest, true, true, true); + emit xrefSignal(rvaToVa(getInitialSelection())); } void TraceDump::hexAsciiSlot() diff --git a/src/gui/Src/Tracer/TraceDump.h b/src/gui/Src/Tracer/TraceDump.h index 2500b37657..d91b73a610 100644 --- a/src/gui/Src/Tracer/TraceDump.h +++ b/src/gui/Src/Tracer/TraceDump.h @@ -28,12 +28,13 @@ class TraceDump : public HexDump signals: void displayReferencesWidget(); void showDisassemblyTab(duint selectionStart, duint selectionEnd, duint firstAddress); + void xrefSignal(duint addr); public slots: void gotoExpressionSlot(); //void gotoFileOffsetSlot(); - void gotoStartSlot(); - void gotoEndSlot(); + //void gotoStartSlot(); + //void gotoEndSlot(); //void gotoPreviousReferenceSlot(); //void gotoNextReferenceSlot(); @@ -79,6 +80,8 @@ public slots: void selectionUpdatedSlot(); //void syncWithExpressionSlot();//TODO: Do we really need to sync with expression here? + void gotoXrefSlot(); + void headerButtonReleasedSlot(duint colIndex); private: @@ -92,7 +95,7 @@ public slots: GotoDialog* mGoto = nullptr; GotoDialog* mGotoOffset = nullptr; - //TraceBrowser* mDisas; + TraceBrowser* mDisas; //CPUMultiDump* mMultiDump; int mAsciiSeparator = 0; diff --git a/src/gui/Src/Tracer/TraceStack.cpp b/src/gui/Src/Tracer/TraceStack.cpp index dff466114b..4fc7738452 100644 --- a/src/gui/Src/Tracer/TraceStack.cpp +++ b/src/gui/Src/Tracer/TraceStack.cpp @@ -134,27 +134,29 @@ void TraceStack::setupContextMenu() mMenuBuilder->addMenu(makeMenu(DIcon("goto"), tr("&Go to")), gotoMenu); + mMenuBuilder->addAction(makeShortcutAction(DIcon("xrefs"), tr("xrefs..."), SLOT(gotoXrefSlot()), "ActionXrefs")); + //Freeze the stack //mMenuBuilder->addAction(mFreezeStack = makeShortcutAction(DIcon("freeze"), tr("Freeze the stack"), SLOT(freezeStackSlot()), "ActionFreezeStack")); //mFreezeStack->setCheckable(true); //Follow in Memory Map - mCommonActions->build(mMenuBuilder, CommonActions::ActionMemoryMap | CommonActions::ActionDump | CommonActions::ActionDumpData); + //mCommonActions->build(mMenuBuilder, CommonActions::ActionMemoryMap | CommonActions::ActionDump | CommonActions::ActionDumpData); //Follow in Stack - auto followStackName = ArchValue(tr("Follow DWORD in &Stack"), tr("Follow QWORD in &Stack")); - mFollowStack = makeAction(DIcon("stack"), followStackName, SLOT(followStackSlot())); - mFollowStack->setShortcutContext(Qt::WidgetShortcut); - mFollowStack->setShortcut(QKeySequence("enter")); - mMenuBuilder->addAction(mFollowStack, [this](QMenu*) - { - duint ptr; - if(!DbgMemRead(rvaToVa(getInitialSelection()), (unsigned char*)&ptr, sizeof(ptr))) - return false; - duint stackBegin = mMemPage->getBase(); - duint stackEnd = stackBegin + mMemPage->getSize(); - return ptr >= stackBegin && ptr < stackEnd; - }); + //auto followStackName = ArchValue(tr("Follow DWORD in &Stack"), tr("Follow QWORD in &Stack")); + //mFollowStack = makeAction(DIcon("stack"), followStackName, SLOT(followStackSlot())); + //mFollowStack->setShortcutContext(Qt::WidgetShortcut); + //mFollowStack->setShortcut(QKeySequence("enter")); + //mMenuBuilder->addAction(mFollowStack, [this](QMenu*) + //{ + // duint ptr; + // if(!DbgMemRead(rvaToVa(getInitialSelection()), (unsigned char*)&ptr, sizeof(ptr))) + // return false; + // duint stackBegin = mMemPage->getBase(); + // duint stackEnd = stackBegin + mMemPage->getSize(); + // return ptr >= stackBegin && ptr < stackEnd; + //}); //Follow in Disassembler auto disasmIcon = DIcon(ArchValue("processor32", "processor64")); @@ -588,6 +590,11 @@ void TraceStack::followStackSlot() //} } +void TraceStack::gotoXrefSlot() +{ + emit xrefSignal(rvaToVa(getInitialSelection())); +} + void TraceStack::binaryCopySlot() { HexEditDialog hexEdit(this); diff --git a/src/gui/Src/Tracer/TraceStack.h b/src/gui/Src/Tracer/TraceStack.h index a3daa18fe7..5460fc1934 100644 --- a/src/gui/Src/Tracer/TraceStack.h +++ b/src/gui/Src/Tracer/TraceStack.h @@ -31,12 +31,14 @@ class TraceStack : public HexDump signals: void displayReferencesWidget(); + void xrefSignal(duint addr); public slots: void stackDumpAt(duint addr, duint csp); void gotoCspSlot(); void gotoCbpSlot(); void gotoExpressionSlot(); + void gotoXrefSlot(); //void selectionUpdatedSlot(); void followDisasmSlot(); void followStackSlot(); diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index 9c3a656b51..f21d4049f1 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -6,6 +6,7 @@ #include "TraceStack.h" #include "TraceFileReader.h" #include "TraceRegisters.h" +#include "TraceXrefBrowseDialog.h" #include "StdTable.h" #include "CPUInfoBox.h" @@ -24,12 +25,14 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q mMemoryPage = new TraceFileDumpMemoryPage(mTraceFile->getDump(), this); mDump = new TraceDump(architecture, mTraceBrowser, mMemoryPage, this); mStack = new TraceStack(architecture, mTraceBrowser, mMemoryPage, this); + mXrefDlg = nullptr; } else { mMemoryPage = nullptr; mDump = nullptr; mStack = nullptr; + mXrefDlg = nullptr; } mGeneralRegs = new TraceRegisters(this); //disasm @@ -68,9 +71,11 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q { //dump ui->mBotLeftFrameLayout->addWidget(mDump); + connect(mDump, SIGNAL(xrefSignal(duint)), this, SLOT(xrefSlot(duint))); //stack ui->mBotRightFrameLayout->addWidget(mStack); + connect(mStack, SIGNAL(xrefSignal(duint)), this, SLOT(xrefSlot(duint))); } ui->mTopHSplitter->setSizes(QList({1000, 1})); @@ -122,6 +127,17 @@ void TraceWidget::traceSelectionChanged(unsigned long long selection) mGeneralRegs->setRegisters(®isters); } +void TraceWidget::xrefSlot(duint addr) +{ + if(!mXrefDlg) + mXrefDlg = new TraceXrefBrowseDialog(this); + mXrefDlg->setup(mTraceBrowser->getInitialSelection(), addr, mTraceFile, [this](duint addr) + { + mTraceBrowser->gotoIndexSlot(addr); + }); + mXrefDlg->showNormal(); +} + void TraceWidget::parseFinishedSlot() { duint initialAddress; diff --git a/src/gui/Src/Tracer/TraceWidget.h b/src/gui/Src/Tracer/TraceWidget.h index 9dcedc171d..9ae3443d60 100644 --- a/src/gui/Src/Tracer/TraceWidget.h +++ b/src/gui/Src/Tracer/TraceWidget.h @@ -13,6 +13,7 @@ class TraceInfoBox; class TraceDump; class TraceStack; class TraceFileReader; +class TraceXrefBrowseDialog; namespace Ui { @@ -34,6 +35,7 @@ protected slots: void traceSelectionChanged(unsigned long long selection); void parseFinishedSlot(); void closeFileSlot(); + void xrefSlot(duint addr); protected: TraceFileReader* mTraceFile; @@ -43,6 +45,7 @@ protected slots: TraceRegisters* mGeneralRegs; TraceFileDumpMemoryPage* mMemoryPage; TraceStack* mStack; + TraceXrefBrowseDialog* mXrefDlg; private: Ui::TraceWidget* ui; diff --git a/src/gui/Src/Tracer/TraceXrefBrowseDialog.cpp b/src/gui/Src/Tracer/TraceXrefBrowseDialog.cpp new file mode 100644 index 0000000000..9d017b7368 --- /dev/null +++ b/src/gui/Src/Tracer/TraceXrefBrowseDialog.cpp @@ -0,0 +1,160 @@ +#include "TraceXrefBrowseDialog.h" +#include "ui_XrefBrowseDialog.h" +#include "TraceFileReader.h" +#include "TraceFileDump.h" +#include "StringUtil.h" +#include "MiscUtil.h" +#include "MenuBuilder.h" + +TraceXrefBrowseDialog::TraceXrefBrowseDialog(QWidget* parent) : + QDialog(parent), + ui(new Ui::XrefBrowseDialog) +{ + ui->setupUi(this); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint | Qt::MSWindowsFixedSizeDialogHint); + setWindowIcon(DIcon("xrefs")); + setModal(false); + ui->listWidget->setContextMenuPolicy(Qt::CustomContextMenu); + + setupContextMenu(); +} + +QString TraceXrefBrowseDialog::GetFunctionSymbol(duint addr) +{ + QString line; + char clabel[MAX_LABEL_SIZE] = ""; + + DbgGetLabelAt(addr, SEG_DEFAULT, clabel); + if(*clabel) + line = QString(clabel); + else + { + duint start; + if(DbgFunctionGet(addr, &start, nullptr) && DbgGetLabelAt(start, SEG_DEFAULT, clabel) && start != addr) + line = QString("%1+%2").arg(clabel).arg(ToHexString(addr - start)); + else + line = QString("%1").arg(ToHexString(addr)); + } + + return line; +} + +void TraceXrefBrowseDialog::setup(duint index, duint address, TraceFileReader* traceFile, GotoFunction gotoFunction) +{ + auto dump = traceFile->getDump(); + mXrefInfo.clear(); + mAddress = index; + mGotoFunction = std::move(gotoFunction); + mPrevSelectionSize = 0; + ui->listWidget->clear(); + auto xrefInfo = dump->getReferences(address, address); + mXrefInfo.reserve(xrefInfo.size()); + for(auto & i : xrefInfo) + { + mXrefInfo.emplace_back(TRACE_XREF_RECORD({i, traceFile->Registers(i).regcontext.cip, XREF_DATA})); + } + + setWindowTitle(QString(tr("xrefs at <%1>")).arg(GetFunctionSymbol(address))); + for(duint i = 0; i < mXrefInfo.size(); i++) + { + Zydis zydis; + std::string disasm; + unsigned char data[16] = { 0xCC }; + int size; + traceFile->OpCode(mXrefInfo[i].index, data, &size); + zydis.Disassemble(mXrefInfo[i].addr, data); + if(zydis.Success()) + { + disasm = zydis.InstructionText(); + ui->listWidget->addItem(QString::fromStdString(disasm)); + } + else + ui->listWidget->addItem("???"); + } + ui->listWidget->setCurrentRow(0); + ui->listWidget->setFocus(); +} + +void TraceXrefBrowseDialog::setupContextMenu() +{ + mMenu = new MenuBuilder(this); + auto mCopyMenu = new MenuBuilder(mMenu); + mCopyMenu->addAction(makeAction(tr("Selected xref"), SLOT(copyThisSlot()))); + mCopyMenu->addAction(makeAction(tr("All xrefs"), SLOT(copyAllSlot()))); + mMenu->addMenu(makeMenu(DIcon("copy"), tr("Copy")), mCopyMenu); + mMenu->loadFromConfig(); +} + +void TraceXrefBrowseDialog::changeAddress(duint address) +{ + mGotoFunction(address); +} + +TraceXrefBrowseDialog::~TraceXrefBrowseDialog() +{ + delete ui; +} + +void TraceXrefBrowseDialog::on_listWidget_itemDoubleClicked(QListWidgetItem*) +{ + accept(); +} + +void TraceXrefBrowseDialog::on_listWidget_itemSelectionChanged() +{ + if(ui->listWidget->selectedItems().size() != mPrevSelectionSize) + { + duint address; + if(mPrevSelectionSize == 0) + address = mXrefInfo[ui->listWidget->currentRow()].index; + else + address = mAddress; + + changeAddress(address); + } + mPrevSelectionSize = ui->listWidget->selectedItems().size(); +} + +void TraceXrefBrowseDialog::on_listWidget_currentRowChanged(int row) +{ + if(ui->listWidget->selectedItems().size() != 0) + { + duint address = mXrefInfo[row].index; + changeAddress(address); + } +} + +void TraceXrefBrowseDialog::on_XrefBrowseDialog_rejected() +{ + mGotoFunction(mAddress); +} + +void TraceXrefBrowseDialog::on_listWidget_itemClicked(QListWidgetItem*) +{ + on_listWidget_currentRowChanged(ui->listWidget->currentRow()); +} + +void TraceXrefBrowseDialog::on_listWidget_customContextMenuRequested(const QPoint & pos) +{ + QMenu menu(this); + mMenu->build(&menu); + menu.exec(ui->listWidget->mapToGlobal(pos)); +} + +void TraceXrefBrowseDialog::copyThisSlot() +{ + Bridge::CopyToClipboard(ToHexString(mXrefInfo[ui->listWidget->currentRow()].index) + " " + ToPtrString(mXrefInfo[ui->listWidget->currentRow()].addr) + " " + ui->listWidget->selectedItems()[0]->text()); +} + +void TraceXrefBrowseDialog::copyAllSlot() +{ + QString temp; + for(int i = 0; i < ui->listWidget->count(); i++) + { + temp.append(ToHexString(mXrefInfo[i].index) + " "); + temp.append(ToPtrString(mXrefInfo[i].addr) + " "); + temp.append(ui->listWidget->selectedItems()[0]->text()); + temp.append("\r\n"); + } + Bridge::CopyToClipboard(temp); +} diff --git a/src/gui/Src/Tracer/TraceXrefBrowseDialog.h b/src/gui/Src/Tracer/TraceXrefBrowseDialog.h new file mode 100644 index 0000000000..4bab769fa1 --- /dev/null +++ b/src/gui/Src/Tracer/TraceXrefBrowseDialog.h @@ -0,0 +1,55 @@ +#pragma once + +#include "Bridge.h" +#include "ActionHelpers.h" +#include +#include + +namespace Ui +{ + class XrefBrowseDialog; +} + +class TraceFileReader; +class TraceFileDump; + +class TraceXrefBrowseDialog : public QDialog, public ActionHelper +{ + Q_OBJECT + +public: + explicit TraceXrefBrowseDialog(QWidget* parent); + ~TraceXrefBrowseDialog(); + using GotoFunction = std::function; + void setup(duint index, duint address, TraceFileReader* traceFile, GotoFunction gotoFunction); + +private slots: + void on_listWidget_itemDoubleClicked(QListWidgetItem* item); + void on_listWidget_itemSelectionChanged(); + void on_listWidget_currentRowChanged(int currentRow); + void on_XrefBrowseDialog_rejected(); + void on_listWidget_itemClicked(QListWidgetItem* item); + void on_listWidget_customContextMenuRequested(const QPoint & pos); + + void copyThisSlot(); + void copyAllSlot(); + +private: + Ui::XrefBrowseDialog* ui; // This uses the same dialog UI as XrefBrowseDialog + + void changeAddress(duint address); + void setupContextMenu(); + static QString GetFunctionSymbol(duint addr); + + typedef struct + { + unsigned long long index; + duint addr; + XREFTYPE type; + } TRACE_XREF_RECORD; + std::vector mXrefInfo; + duint mAddress; + int mPrevSelectionSize; + MenuBuilder* mMenu; + GotoFunction mGotoFunction; +}; diff --git a/src/gui/Src/Utils/Configuration.cpp b/src/gui/Src/Utils/Configuration.cpp index 25e8b2f504..7801322791 100644 --- a/src/gui/Src/Utils/Configuration.cpp +++ b/src/gui/Src/Utils/Configuration.cpp @@ -316,6 +316,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false) insertMenuBuilderBools(&guiBool, "TraceBrowser", 50); //TraceBrowser insertMenuBuilderBools(&guiBool, "TraceDump", 50); //Trace Dump insertMenuBuilderBools(&guiBool, "TraceStack", 50); //Trace Stack + insertMenuBuilderBools(&guiBool, "TraceXrefBrowseDialog", 50); //TraceXrefBrowseDialog defaultBools.insert("Gui", guiBool); QMap guiUint; diff --git a/src/gui/x64dbg.pro b/src/gui/x64dbg.pro index 590cb61f0c..872a4a6ae1 100644 --- a/src/gui/x64dbg.pro +++ b/src/gui/x64dbg.pro @@ -87,6 +87,7 @@ SOURCES += \ Src/Tracer/TraceRegisters.cpp \ Src/Tracer/TraceStack.cpp \ Src/Tracer/TraceWidget.cpp \ + Src/Tracer/TraceXrefBrowseDialog.cpp \ Src/Utils/CommonActions.cpp \ Src/main.cpp \ Src/Gui/MainWindow.cpp \ @@ -212,6 +213,7 @@ HEADERS += \ Src/Tracer/TraceRegisters.h \ Src/Tracer/TraceStack.h \ Src/Tracer/TraceWidget.h \ + Src/Tracer/TraceXrefBrowseDialog.h \ Src/Utils/CommonActions.h \ Src/main.h \ Src/Gui/MainWindow.h \ From a461951d074ea4c8745f0e30b0bcef1cbd467949 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Sat, 20 Apr 2024 18:17:31 +0800 Subject: [PATCH 26/33] Add Xrefs to trace disassembler too --- src/gui/Src/Tracer/TraceBrowser.cpp | 20 +++++++++++++++++--- src/gui/Src/Tracer/TraceBrowser.h | 2 ++ src/gui/Src/Tracer/TraceRegisters.cpp | 4 ++-- src/gui/Src/Tracer/TraceWidget.cpp | 1 + src/gui/Src/Tracer/TraceXrefBrowseDialog.cpp | 13 ++++++++----- src/gui/Src/Tracer/TraceXrefBrowseDialog.h | 1 - 6 files changed, 30 insertions(+), 11 deletions(-) diff --git a/src/gui/Src/Tracer/TraceBrowser.cpp b/src/gui/Src/Tracer/TraceBrowser.cpp index fc1ab3a63d..4494a8745a 100644 --- a/src/gui/Src/Tracer/TraceBrowser.cpp +++ b/src/gui/Src/Tracer/TraceBrowser.cpp @@ -882,6 +882,11 @@ void TraceBrowser::setupRightClickContextMenu() }); mMenuBuilder->addMenu(makeMenu(DIcon("goto"), tr("Go to")), gotoMenu); + mMenuBuilder->addAction(makeShortcutAction(DIcon("xrefs"), tr("xrefs..."), SLOT(gotoXrefSlot()), "ActionXrefs"), [this](QMenu*) + { + return !Config()->getBool("Gui", "DisableTraceDump"); // Do not show xrefs when dump is disabled + }); + MenuBuilder* searchMenu = new MenuBuilder(this, mTraceFileNotNull); searchMenu->addAction(makeAction(DIcon("search_for_constant"), tr("Address/Constant"), SLOT(searchConstantSlot()))); searchMenu->addAction(makeAction(DIcon("memory-map"), tr("Memory Reference"), SLOT(searchMemRefSlot()))); @@ -940,9 +945,12 @@ void TraceBrowser::setupRightClickContextMenu() } return true; }); - mMenuBuilder->addAction(makeAction(DIcon("close"), tr("Close recording"), SLOT(closeFileSlot())), mTraceFileNotNull); - mMenuBuilder->addAction(makeAction(DIcon("delete"), tr("Delete recording"), SLOT(closeDeleteSlot())), mTraceFileNotNull); - mMenuBuilder->addAction(makeShortcutAction(DIcon("browseinexplorer"), tr("Browse in Explorer"), SLOT(browseInExplorerSlot()), "ActionBrowseInExplorer"), mTraceFileNotNull); + mMenuBuilder->addAction(makeAction(DIcon("close"), tr("Close recording"), SLOT(closeFileSlot())), mTraceFileNotNull) + ->setStatusTip(tr("Close the trace file tab, and stop recording trace.")); + mMenuBuilder->addAction(makeAction(DIcon("delete"), tr("Delete recording"), SLOT(closeDeleteSlot())), mTraceFileNotNull) + ->setStatusTip(tr("Delete the trace file from disk, and stop recording trace.")); + mMenuBuilder->addAction(makeShortcutAction(DIcon("browseinexplorer"), tr("Browse in Explorer"), SLOT(browseInExplorerSlot()), "ActionBrowseInExplorer"), mTraceFileNotNull) + ->setStatusTip(tr("Open the trace file in Explorer.")); mMenuBuilder->loadFromConfig(); } @@ -1393,6 +1401,12 @@ void TraceBrowser::gotoPreviousSlot() disasm(mHistory.historyPrev(), false); } + +void TraceBrowser::gotoXrefSlot() +{ + emit xrefSignal(getTraceFile()->Registers(getInitialSelection()).regcontext.cip); +} + void TraceBrowser::copyCipSlot() { QString clipboard; diff --git a/src/gui/Src/Tracer/TraceBrowser.h b/src/gui/Src/Tracer/TraceBrowser.h index d40343ab40..0ae247e071 100644 --- a/src/gui/Src/Tracer/TraceBrowser.h +++ b/src/gui/Src/Tracer/TraceBrowser.h @@ -147,6 +147,7 @@ class TraceBrowser : public AbstractTableView void displayReferencesWidget(); void displayLogWidget(); void selectionChanged(unsigned long long selection); + void xrefSignal(duint addr); void closeFile(); public slots: @@ -164,6 +165,7 @@ public slots: void rtrSlot(); void gotoPreviousSlot(); void gotoNextSlot(); + void gotoXrefSlot(); void enableHighlightingModeSlot(); void mnemonicBriefSlot(); void mnemonicHelpSlot(); diff --git a/src/gui/Src/Tracer/TraceRegisters.cpp b/src/gui/Src/Tracer/TraceRegisters.cpp index 3e252abc13..05b5590367 100644 --- a/src/gui/Src/Tracer/TraceRegisters.cpp +++ b/src/gui/Src/Tracer/TraceRegisters.cpp @@ -67,10 +67,10 @@ void TraceRegisters::displayCustomContextMenuSlot(QPoint pos) menu.addAction(mDisplayMMX); } - if((!mNoChange.contains(mSelected)) || + if(((!mNoChange.contains(mSelected)) || mSelected == LastError || mSelected == LastStatus || - mSelected == CIP) + mSelected == CIP) && DbgIsDebugging()) { menu.addAction(wCM_SetCurrentRegister); } diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index f21d4049f1..9f89a6b7f5 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -69,6 +69,7 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q if(mDump) { + connect(mTraceBrowser, SIGNAL(xrefSignal(duint)), this, SLOT(xrefSlot(duint))); //dump ui->mBotLeftFrameLayout->addWidget(mDump); connect(mDump, SIGNAL(xrefSignal(duint)), this, SLOT(xrefSlot(duint))); diff --git a/src/gui/Src/Tracer/TraceXrefBrowseDialog.cpp b/src/gui/Src/Tracer/TraceXrefBrowseDialog.cpp index 9d017b7368..1767d58c82 100644 --- a/src/gui/Src/Tracer/TraceXrefBrowseDialog.cpp +++ b/src/gui/Src/Tracer/TraceXrefBrowseDialog.cpp @@ -51,25 +51,28 @@ void TraceXrefBrowseDialog::setup(duint index, duint address, TraceFileReader* t mXrefInfo.reserve(xrefInfo.size()); for(auto & i : xrefInfo) { - mXrefInfo.emplace_back(TRACE_XREF_RECORD({i, traceFile->Registers(i).regcontext.cip, XREF_DATA})); + mXrefInfo.emplace_back(TRACE_XREF_RECORD({i, traceFile->Registers(i).regcontext.cip})); } setWindowTitle(QString(tr("xrefs at <%1>")).arg(GetFunctionSymbol(address))); for(duint i = 0; i < mXrefInfo.size(); i++) { Zydis zydis; - std::string disasm; + QString disasm; unsigned char data[16] = { 0xCC }; int size; traceFile->OpCode(mXrefInfo[i].index, data, &size); zydis.Disassemble(mXrefInfo[i].addr, data); if(zydis.Success()) { - disasm = zydis.InstructionText(); - ui->listWidget->addItem(QString::fromStdString(disasm)); + disasm = QString::fromStdString(zydis.InstructionText()); } else - ui->listWidget->addItem("???"); + { + disasm = "???"; + } + disasm = traceFile->getIndexText(mXrefInfo[i].index) + ": " + disasm; + ui->listWidget->addItem(disasm); } ui->listWidget->setCurrentRow(0); ui->listWidget->setFocus(); diff --git a/src/gui/Src/Tracer/TraceXrefBrowseDialog.h b/src/gui/Src/Tracer/TraceXrefBrowseDialog.h index 4bab769fa1..4735e19950 100644 --- a/src/gui/Src/Tracer/TraceXrefBrowseDialog.h +++ b/src/gui/Src/Tracer/TraceXrefBrowseDialog.h @@ -45,7 +45,6 @@ private slots: { unsigned long long index; duint addr; - XREFTYPE type; } TRACE_XREF_RECORD; std::vector mXrefInfo; duint mAddress; From 9749d1549b95b0ed81290c2667def5a3cfd16c93 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Mon, 22 Apr 2024 18:14:15 +0800 Subject: [PATCH 27/33] Fix showing reference and log from trace --- src/gui/Src/Gui/MainWindow.cpp | 3 +-- src/gui/Src/Tracer/TraceBrowser.cpp | 4 ++-- src/gui/Src/Tracer/TraceBrowser.h | 1 - src/gui/Src/Tracer/TraceManager.cpp | 4 ++++ src/gui/Src/Tracer/TraceManager.h | 3 +++ src/gui/Src/Tracer/TraceWidget.cpp | 6 ++++++ src/gui/Src/Tracer/TraceWidget.h | 2 ++ 7 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/gui/Src/Gui/MainWindow.cpp b/src/gui/Src/Gui/MainWindow.cpp index a21f682924..1a8955fba5 100644 --- a/src/gui/Src/Gui/MainWindow.cpp +++ b/src/gui/Src/Gui/MainWindow.cpp @@ -230,8 +230,7 @@ MainWindow::MainWindow(QWidget* parent) mTraceWidget = new TraceManager(this); mTraceWidget->setWindowTitle(tr("Trace")); mTraceWidget->setWindowIcon(DIcon("trace")); - //connect(mTraceWidget->getTraceBrowser(), SIGNAL(displayReferencesWidget()), this, SLOT(displayReferencesWidget())); - //connect(mTraceWidget->getTraceBrowser(), SIGNAL(displayLogWidget()), this, SLOT(displayLogWidget())); + connect(mTraceWidget, SIGNAL(displayLogWidget()), this, SLOT(displayLogWidget())); mTabWidget = new MHTabWidget(this, true, true); diff --git a/src/gui/Src/Tracer/TraceBrowser.cpp b/src/gui/Src/Tracer/TraceBrowser.cpp index 4494a8745a..1cb0014aeb 100644 --- a/src/gui/Src/Tracer/TraceBrowser.cpp +++ b/src/gui/Src/Tracer/TraceBrowser.cpp @@ -1807,7 +1807,7 @@ void TraceBrowser::searchConstantSlot() { auto ticks = GetTickCount(); int count = TraceFileSearchConstantRange(getTraceFile(), constantDlg.getVal(), constantDlg.getVal()); - emit displayReferencesWidget(); + GuiShowReferences(); GuiAddLogMessage(tr("%1 result(s) in %2ms\n").arg(count).arg(GetTickCount() - ticks).toUtf8().constData()); } } @@ -1820,7 +1820,7 @@ void TraceBrowser::searchMemRefSlot() { auto ticks = GetTickCount(); int count = TraceFileSearchMemReference(getTraceFile(), memRefDlg.getVal()); - emit displayReferencesWidget(); + GuiShowReferences(); GuiAddLogMessage(tr("%1 result(s) in %2ms\n").arg(count).arg(GetTickCount() - ticks).toUtf8().constData()); } } diff --git a/src/gui/Src/Tracer/TraceBrowser.h b/src/gui/Src/Tracer/TraceBrowser.h index 0ae247e071..6c8d3fda49 100644 --- a/src/gui/Src/Tracer/TraceBrowser.h +++ b/src/gui/Src/Tracer/TraceBrowser.h @@ -144,7 +144,6 @@ class TraceBrowser : public AbstractTableView int paintFunctionGraphic(QPainter* painter, int x, int y, Function_t funcType, bool loop); signals: - void displayReferencesWidget(); void displayLogWidget(); void selectionChanged(unsigned long long selection); void xrefSignal(duint addr); diff --git a/src/gui/Src/Tracer/TraceManager.cpp b/src/gui/Src/Tracer/TraceManager.cpp index c34b2c24dc..f2e5774fa2 100644 --- a/src/gui/Src/Tracer/TraceManager.cpp +++ b/src/gui/Src/Tracer/TraceManager.cpp @@ -60,6 +60,10 @@ void TraceManager::openSlot(const QString & path) { closeTab(index); }); + connect(newView, &TraceWidget::displayLogWidget, this, [this]() + { + emit displayLogWidget(); + }); } void TraceManager::closeTab(int index) diff --git a/src/gui/Src/Tracer/TraceManager.h b/src/gui/Src/Tracer/TraceManager.h index cfd27675f9..01d7f0192c 100644 --- a/src/gui/Src/Tracer/TraceManager.h +++ b/src/gui/Src/Tracer/TraceManager.h @@ -16,6 +16,9 @@ class TraceManager : public QTabWidget void contextMenuEvent(QContextMenuEvent* event) override; +signals: + void displayLogWidget(); + public slots: void open(); void openSlot(const QString &); diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index 9f89a6b7f5..60914b16d2 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -53,6 +53,7 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q button_changeview->setStyleSheet("Text-align:left;padding: 4px;padding-left: 10px;"); connect(button_changeview, SIGNAL(clicked()), mGeneralRegs, SLOT(onChangeFPUViewAction())); connect(mTraceBrowser, SIGNAL(selectionChanged(unsigned long long)), this, SLOT(traceSelectionChanged(unsigned long long))); + connect(mTraceBrowser, SIGNAL(displayLogWidget()), this, SLOT(displayLogWidgetSlot())); connect(mTraceFile, SIGNAL(parseFinished()), this, SLOT(parseFinishedSlot())); connect(mTraceBrowser, SIGNAL(closeFile()), this, SLOT(closeFileSlot())); @@ -189,3 +190,8 @@ void TraceWidget::closeFileSlot() { emit closeFile(); } + +void TraceWidget::displayLogWidgetSlot() +{ + emit displayLogWidget(); +} diff --git a/src/gui/Src/Tracer/TraceWidget.h b/src/gui/Src/Tracer/TraceWidget.h index 9ae3443d60..eefc207f35 100644 --- a/src/gui/Src/Tracer/TraceWidget.h +++ b/src/gui/Src/Tracer/TraceWidget.h @@ -30,8 +30,10 @@ class TraceWidget : public QWidget signals: void closeFile(); + void displayLogWidget(); protected slots: + void displayLogWidgetSlot(); void traceSelectionChanged(unsigned long long selection); void parseFinishedSlot(); void closeFileSlot(); From 8d9f129af6a78b009fb118f17c5006fe5187603e Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Sat, 13 Jul 2024 17:13:01 +0800 Subject: [PATCH 28/33] Allow detaching a trace tab --- src/gui/Src/Gui/TabWidget.cpp | 10 ++++++++- src/gui/Src/Gui/TabWidget.h | 2 +- src/gui/Src/Tracer/TraceManager.cpp | 33 +++++++++++++++++------------ src/gui/Src/Tracer/TraceManager.h | 7 +++--- 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/gui/Src/Gui/TabWidget.cpp b/src/gui/Src/Gui/TabWidget.cpp index ae1b231744..17ed6364c0 100644 --- a/src/gui/Src/Gui/TabWidget.cpp +++ b/src/gui/Src/Gui/TabWidget.cpp @@ -58,7 +58,7 @@ QList MHTabWidget::windows() return mWindows; } -// Add a tab +// Add a tab with icon int MHTabWidget::addTabEx(QWidget* widget, const QIcon & icon, const QString & label, const QString & nativeName) { mNativeNames.append(nativeName); @@ -148,7 +148,15 @@ void MHTabWidget::DetachTab(int index, const QPoint & dropPoint) void MHTabWidget::DeleteTab(int index) { QWidget* w = widget(index); + if(index >= QTabWidget::count()) + { + // The tab is detached, so need to re-attach, transfer the widget back to tab widget from detached window + MHDetachedWindow* window = dynamic_cast(widget(index)->parent()); + index = window->mPreviousIndex; + AttachTab(window); + } mHistory.removeAll((MIDPKey)w); + // Delete tab removeTab(index); mNativeNames.removeAt(index); } diff --git a/src/gui/Src/Gui/TabWidget.h b/src/gui/Src/Gui/TabWidget.h index ab173f54f4..e7dfb2a34d 100644 --- a/src/gui/Src/Gui/TabWidget.h +++ b/src/gui/Src/Gui/TabWidget.h @@ -36,7 +36,7 @@ class MHTabWidget: public QTabWidget, public MultiItemsDataProvider public slots: void AttachTab(QWidget* parent); void DetachTab(int index, const QPoint &); - void DeleteTab(int index); + virtual void DeleteTab(int index); void tabMoved(int from, int to); void OnDetachFocused(QWidget* parent); void currentChanged(int index); diff --git a/src/gui/Src/Tracer/TraceManager.cpp b/src/gui/Src/Tracer/TraceManager.cpp index f2e5774fa2..339a6470a3 100644 --- a/src/gui/Src/Tracer/TraceManager.cpp +++ b/src/gui/Src/Tracer/TraceManager.cpp @@ -1,29 +1,28 @@ #include #include #include "TraceManager.h" +#include "TraceWidget.h" #include "TraceBrowser.h" #include "BrowseDialog.h" #include "MRUList.h" #include "StringUtil.h" #include "MiscUtil.h" +#include "TabBar.h" -TraceManager::TraceManager(QWidget* parent) : QTabWidget(parent) +TraceManager::TraceManager(QWidget* parent) : MHTabWidget(parent, true, true) { - setMovable(true); - - //MRU + //MRU List mMRUList = new MRUList(this, "Recent Trace Files"); connect(mMRUList, SIGNAL(openFile(QString)), this, SLOT(openSlot(QString))); mMRUList->load(); - //Close All Tabs - mCloseAllTabs = new QPushButton(this); + //Close All Tabs Button + QPushButton* mCloseAllTabs = new QPushButton(this); mCloseAllTabs->setIcon(DIcon("close-all-tabs")); mCloseAllTabs->setToolTip(tr("Close All Tabs")); connect(mCloseAllTabs, SIGNAL(clicked()), this, SLOT(closeAllTabs())); setCornerWidget(mCloseAllTabs, Qt::TopLeftCorner); - connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(closeTab(int))); connect(Bridge::getBridge(), SIGNAL(openTraceFile(const QString &)), this, SLOT(openSlot(const QString &))); } @@ -51,14 +50,22 @@ void TraceManager::openSlot(const QString & path) { //load the new file TraceWidget* newView = new TraceWidget(Bridge::getArchitecture(), path, this); - addTab(newView, path); //TODO: Proper title + addTabEx(newView, DIcon("trace"), path, path); //TODO: Proper title int index = count() - 1; setCurrentIndex(index); mMRUList->addEntry(path); mMRUList->save(); - connect(newView, &TraceWidget::closeFile, this, [index, this]() + connect(newView, &TraceWidget::closeFile, this, [newView, this]() { - closeTab(index); + // Find index, it could be moved by the user to another position + for(int index = 0; index < count(); index++) + { + if(widget(index) == newView) + { + DeleteTab(index); + return; + } + } }); connect(newView, &TraceWidget::displayLogWidget, this, [this]() { @@ -66,21 +73,21 @@ void TraceManager::openSlot(const QString & path) }); } -void TraceManager::closeTab(int index) +void TraceManager::DeleteTab(int index) { auto view = qobject_cast(widget(index)); if(view) { - removeTab(index); view->deleteLater(); // It needs to return from close event before we can delete } + MHTabWidget::DeleteTab(index); // Tell the parent class to close the tab } void TraceManager::closeAllTabs() { while(count()) { - closeTab(count() - 1); + DeleteTab(count() - 1); } } diff --git a/src/gui/Src/Tracer/TraceManager.h b/src/gui/Src/Tracer/TraceManager.h index 01d7f0192c..ccf01c18c1 100644 --- a/src/gui/Src/Tracer/TraceManager.h +++ b/src/gui/Src/Tracer/TraceManager.h @@ -3,11 +3,11 @@ #include #include #include -#include "TraceWidget.h" +#include "TabWidget.h" class MRUList; -class TraceManager : public QTabWidget +class TraceManager : public MHTabWidget { Q_OBJECT public: @@ -22,11 +22,10 @@ class TraceManager : public QTabWidget public slots: void open(); void openSlot(const QString &); - void closeTab(int index); + void DeleteTab(int index) override; void closeAllTabs(); void toggleTraceRecording(); private: MRUList* mMRUList; - QPushButton* mCloseAllTabs; }; From c5794519a869743fe354c5cc0b1aa249840a5731 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Sat, 13 Jul 2024 17:57:25 +0800 Subject: [PATCH 29/33] Add load dump button and disable auto dump loading by default --- src/gui/Src/Gui/SettingsDialog.ui | 4 +- src/gui/Src/Tracer/TraceBrowser.cpp | 5 +- src/gui/Src/Tracer/TraceFileDump.cpp | 2 + src/gui/Src/Tracer/TraceFileDump.h | 9 +++ src/gui/Src/Tracer/TraceFileReader.cpp | 4 +- src/gui/Src/Tracer/TraceFileSearch.cpp | 2 +- src/gui/Src/Tracer/TraceWidget.cpp | 89 +++++++++++++++++++------- src/gui/Src/Tracer/TraceWidget.h | 5 ++ src/gui/Src/Utils/Configuration.cpp | 2 +- 9 files changed, 89 insertions(+), 33 deletions(-) diff --git a/src/gui/Src/Gui/SettingsDialog.ui b/src/gui/Src/Gui/SettingsDialog.ui index 6babbf44dc..8fa727d20b 100644 --- a/src/gui/Src/Gui/SettingsDialog.ui +++ b/src/gui/Src/Gui/SettingsDialog.ui @@ -964,10 +964,10 @@ - Dump in trace view consumes significant memory and CPU resources. It can be disabled if you find it too slow. Already opened trace tabs are not affected. + Dump in trace view consumes significant memory. If disabled, it will not be loaded by default. The user can always load the dump manually. Dump in already opened trace tabs are not disabled until you close them. - Disable dump in trace view + Do not automatically load dump in trace view diff --git a/src/gui/Src/Tracer/TraceBrowser.cpp b/src/gui/Src/Tracer/TraceBrowser.cpp index 1cb0014aeb..50a6a83865 100644 --- a/src/gui/Src/Tracer/TraceBrowser.cpp +++ b/src/gui/Src/Tracer/TraceBrowser.cpp @@ -882,10 +882,7 @@ void TraceBrowser::setupRightClickContextMenu() }); mMenuBuilder->addMenu(makeMenu(DIcon("goto"), tr("Go to")), gotoMenu); - mMenuBuilder->addAction(makeShortcutAction(DIcon("xrefs"), tr("xrefs..."), SLOT(gotoXrefSlot()), "ActionXrefs"), [this](QMenu*) - { - return !Config()->getBool("Gui", "DisableTraceDump"); // Do not show xrefs when dump is disabled - }); + mMenuBuilder->addAction(makeShortcutAction(DIcon("xrefs"), tr("xrefs..."), SLOT(gotoXrefSlot()), "ActionXrefs")); MenuBuilder* searchMenu = new MenuBuilder(this, mTraceFileNotNull); searchMenu->addAction(makeAction(DIcon("search_for_constant"), tr("Address/Constant"), SLOT(searchConstantSlot()))); diff --git a/src/gui/Src/Tracer/TraceFileDump.cpp b/src/gui/Src/Tracer/TraceFileDump.cpp index c7d20102c3..087c91fd10 100644 --- a/src/gui/Src/Tracer/TraceFileDump.cpp +++ b/src/gui/Src/Tracer/TraceFileDump.cpp @@ -1,10 +1,12 @@ #include +#include "Configuration.h" #include "TraceFileDump.h" #include "StringUtil.h" TraceFileDump::TraceFileDump() { maxIndex = 0ull; + enabled = false; } TraceFileDump::~TraceFileDump() diff --git a/src/gui/Src/Tracer/TraceFileDump.h b/src/gui/Src/Tracer/TraceFileDump.h index 7b04e905fb..23976cd1da 100644 --- a/src/gui/Src/Tracer/TraceFileDump.h +++ b/src/gui/Src/Tracer/TraceFileDump.h @@ -29,6 +29,14 @@ class TraceFileDump TraceFileDump(); ~TraceFileDump(); void clear(); + inline void setEnabled() + { + enabled = true; + } + inline bool isEnabled() const + { + return enabled; + } // Read a byte at "addr" at the moment given in "index" unsigned char getByte(Key location, bool & success) const; std::vector getBytes(duint addr, duint size, unsigned long long index) const; @@ -50,6 +58,7 @@ class TraceFileDump private: std::map dump; unsigned long long maxIndex; + bool enabled; }; class TraceFileDumpMemoryPage : public MemoryPage diff --git a/src/gui/Src/Tracer/TraceFileReader.cpp b/src/gui/Src/Tracer/TraceFileReader.cpp index 3a3ac606b6..29fc20af33 100644 --- a/src/gui/Src/Tracer/TraceFileReader.cpp +++ b/src/gui/Src/Tracer/TraceFileReader.cpp @@ -101,7 +101,7 @@ void TraceFileReader::parseFinishedSlot() progress.store(0); delete parser; parser = nullptr; - if(Length() > 0 && !Config()->getBool("Gui", "DisableTraceDump")) + if(Length() > 0 && getDump()->isEnabled()) buildDump(0); // initialize dump with first instruction emit parseFinished(); @@ -584,7 +584,7 @@ void TraceFileReader::purgeLastPage() error = false; errorMessage.clear(); length = index; - if(previousEmpty && length > 0 && !Config()->getBool("Gui", "DisableTraceDump")) + if(previousEmpty && length > 0 && getDump()->isEnabled()) buildDump(0); // Initialize dump } catch(std::wstring & errReason) diff --git a/src/gui/Src/Tracer/TraceFileSearch.cpp b/src/gui/Src/Tracer/TraceFileSearch.cpp index 21743cd7d1..295734ddb6 100644 --- a/src/gui/Src/Tracer/TraceFileSearch.cpp +++ b/src/gui/Src/Tracer/TraceFileSearch.cpp @@ -98,7 +98,7 @@ int TraceFileSearchMemReference(TraceFileReader* file, duint address) GuiReferenceAddColumn(100, QCoreApplication::translate("TraceFileSearch", "Disassembly").toUtf8().constData()); GuiReferenceAddCommand(QCoreApplication::translate("TraceFileSearch", "Follow index in trace").toUtf8().constData(), "gototrace 0x$1"); GuiReferenceSetRowCount(0); - bool useTraceDump = !Config()->getBool("Gui", "DisableTraceDump"); + bool useTraceDump = file->getDump()->isEnabled(); if(useTraceDump) { diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index 60914b16d2..04e7990d42 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -1,5 +1,6 @@ #include "TraceWidget.h" #include "ui_TraceWidget.h" +#include #include "TraceBrowser.h" #include "TraceInfoBox.h" #include "TraceDump.h" @@ -20,20 +21,24 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q mTraceFile->Open(fileName); mTraceBrowser = new TraceBrowser(mTraceFile, this); mInfo = new TraceInfoBox(this); + mArchitecture = architecture; if(!Config()->getBool("Gui", "DisableTraceDump")) { + mTraceFile->getDump()->setEnabled(); mMemoryPage = new TraceFileDumpMemoryPage(mTraceFile->getDump(), this); mDump = new TraceDump(architecture, mTraceBrowser, mMemoryPage, this); mStack = new TraceStack(architecture, mTraceBrowser, mMemoryPage, this); - mXrefDlg = nullptr; + mLoadDump = nullptr; } else { mMemoryPage = nullptr; mDump = nullptr; mStack = nullptr; - mXrefDlg = nullptr; + mLoadDump = new QPushButton(tr("Load dump"), this); + connect(mLoadDump, SIGNAL(clicked()), this, SLOT(loadDump())); } + mXrefDlg = nullptr; mGeneralRegs = new TraceRegisters(this); //disasm ui->mTopLeftUpperRightFrameLayout->addWidget(mTraceBrowser); @@ -68,9 +73,9 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q int height = mInfo->getHeight(); ui->mTopLeftLowerFrame->setMinimumHeight(height + 2); + connect(mTraceBrowser, SIGNAL(xrefSignal(duint)), this, SLOT(xrefSlot(duint))); if(mDump) { - connect(mTraceBrowser, SIGNAL(xrefSignal(duint)), this, SLOT(xrefSlot(duint))); //dump ui->mBotLeftFrameLayout->addWidget(mDump); connect(mDump, SIGNAL(xrefSignal(duint)), this, SLOT(xrefSlot(duint))); @@ -79,6 +84,10 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q ui->mBotRightFrameLayout->addWidget(mStack); connect(mStack, SIGNAL(xrefSignal(duint)), this, SLOT(xrefSlot(duint))); } + else + { + ui->mBotLeftFrameLayout->addWidget(mLoadDump); + } ui->mTopHSplitter->setSizes(QList({1000, 1})); ui->mTopLeftVSplitter->setSizes(QList({1000, 1})); @@ -131,6 +140,8 @@ void TraceWidget::traceSelectionChanged(unsigned long long selection) void TraceWidget::xrefSlot(duint addr) { + if(!mDump) + loadDump(); if(!mXrefDlg) mXrefDlg = new TraceXrefBrowseDialog(this); mXrefDlg->setup(mTraceBrowser->getInitialSelection(), addr, mTraceFile, [this](duint addr) @@ -161,26 +172,7 @@ void TraceWidget::parseFinishedSlot() } if(mDump) { - // Setting the initial address of dump view - const int count = mTraceFile->MemoryAccessCount(0); - if(count > 0) - { - // Display source operand - duint address[MAX_MEMORY_OPERANDS]; - duint oldMemory[MAX_MEMORY_OPERANDS]; - duint newMemory[MAX_MEMORY_OPERANDS]; - bool isValid[MAX_MEMORY_OPERANDS]; - mTraceFile->MemoryAccessInfo(0, address, oldMemory, newMemory, isValid); - initialAddress = address[count - 1]; - } - else - { - // No memory operands, so display opcode instead - initialAddress = mTraceFile->Registers(0).regcontext.cip; - } - mDump->printDumpAt(initialAddress, false, true, true); - // Setting the initial address of stack view - mStack->printDumpAt(mTraceFile->Registers(0).regcontext.csp, false, true, true); + setupDumpInitialAddresses(0); } mGeneralRegs->setActive(true); } @@ -195,3 +187,54 @@ void TraceWidget::displayLogWidgetSlot() { emit displayLogWidget(); } + +void TraceWidget::loadDump() +{ + mTraceFile->getDump()->setEnabled(); + mMemoryPage = new TraceFileDumpMemoryPage(mTraceFile->getDump(), this); + auto selection = mTraceBrowser->getInitialSelection(); + mTraceFile->buildDumpTo(selection); // TODO: sometimes this can be slow // TODO: Is it a good idea to build dump index just when opening the file? + mMemoryPage->setSelectedIndex(selection); + mDump = new TraceDump(mArchitecture, mTraceBrowser, mMemoryPage, this); + mStack = new TraceStack(mArchitecture, mTraceBrowser, mMemoryPage, this); + + //dump + ui->mBotLeftFrameLayout->removeWidget(mLoadDump); + delete mLoadDump; + mLoadDump = nullptr; + ui->mBotLeftFrameLayout->addWidget(mDump); + connect(mDump, SIGNAL(xrefSignal(duint)), this, SLOT(xrefSlot(duint))); + mDump->setAccessibleName(tr("Dump")); + + //stack + ui->mBotRightFrameLayout->addWidget(mStack); + connect(mStack, SIGNAL(xrefSignal(duint)), this, SLOT(xrefSlot(duint))); + mStack->setAccessibleName(tr("Stack")); + + setupDumpInitialAddresses(selection); +} + +void TraceWidget::setupDumpInitialAddresses(unsigned long long selection) +{ + // Setting the initial address of dump view + duint initialAddress; + const int count = mTraceFile->MemoryAccessCount(selection); + if(count > 0) + { + // Display source operand + duint address[MAX_MEMORY_OPERANDS]; + duint oldMemory[MAX_MEMORY_OPERANDS]; + duint newMemory[MAX_MEMORY_OPERANDS]; + bool isValid[MAX_MEMORY_OPERANDS]; + mTraceFile->MemoryAccessInfo(selection, address, oldMemory, newMemory, isValid); + initialAddress = address[count - 1]; + } + else + { + // No memory operands, so display opcode instead + initialAddress = mTraceFile->Registers(selection).regcontext.cip; + } + mDump->printDumpAt(initialAddress, false, true, true); + // Setting the initial address of stack view + mStack->printDumpAt(mTraceFile->Registers(selection).regcontext.csp, false, true, true); +} diff --git a/src/gui/Src/Tracer/TraceWidget.h b/src/gui/Src/Tracer/TraceWidget.h index eefc207f35..f3964de38c 100644 --- a/src/gui/Src/Tracer/TraceWidget.h +++ b/src/gui/Src/Tracer/TraceWidget.h @@ -4,6 +4,7 @@ #include "Bridge.h" class QVBoxLayout; +class QPushButton; class CPUWidget; class TraceRegisters; class TraceBrowser; @@ -36,6 +37,7 @@ protected slots: void displayLogWidgetSlot(); void traceSelectionChanged(unsigned long long selection); void parseFinishedSlot(); + void loadDump(); void closeFileSlot(); void xrefSlot(duint addr); @@ -48,7 +50,10 @@ protected slots: TraceFileDumpMemoryPage* mMemoryPage; TraceStack* mStack; TraceXrefBrowseDialog* mXrefDlg; + QPushButton* mLoadDump; + Architecture* mArchitecture; private: Ui::TraceWidget* ui; + void setupDumpInitialAddresses(unsigned long long selection); }; diff --git a/src/gui/Src/Utils/Configuration.cpp b/src/gui/Src/Utils/Configuration.cpp index 7801322791..3205352283 100644 --- a/src/gui/Src/Utils/Configuration.cpp +++ b/src/gui/Src/Utils/Configuration.cpp @@ -295,7 +295,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false) guiBool.insert("Topmost", false); guiBool.insert("CPUDumpStartFromSelect", true); guiBool.insert("CPUStackStartFromSelect", true); - guiBool.insert("DisableTraceDump", false); + guiBool.insert("DisableTraceDump", true); //Named menu settings insertMenuBuilderBools(&guiBool, "CPUDisassembly", 50); //CPUDisassembly insertMenuBuilderBools(&guiBool, "CPUDump", 50); //CPUDump From b7ced72f4a87ee90733c9ae3aa7406b6c242d716 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Sat, 13 Jul 2024 20:42:37 +0800 Subject: [PATCH 30/33] Add feature to go to VA in trace using indexed search --- src/gui/Src/Gui/SettingsDialog.ui | 2 +- src/gui/Src/Tracer/TraceBrowser.cpp | 65 ++++++++++++++++++++++++-- src/gui/Src/Tracer/TraceBrowser.h | 8 +++- src/gui/Src/Tracer/TraceFileDump.cpp | 27 +++++------ src/gui/Src/Tracer/TraceFileDump.h | 2 +- src/gui/Src/Tracer/TraceFileSearch.cpp | 57 ++++------------------ src/gui/Src/Tracer/TraceWidget.cpp | 18 ++++++- src/gui/Src/Tracer/TraceWidget.h | 7 ++- 8 files changed, 116 insertions(+), 70 deletions(-) diff --git a/src/gui/Src/Gui/SettingsDialog.ui b/src/gui/Src/Gui/SettingsDialog.ui index 8fa727d20b..ab5b7a6dff 100644 --- a/src/gui/Src/Gui/SettingsDialog.ui +++ b/src/gui/Src/Gui/SettingsDialog.ui @@ -964,7 +964,7 @@ - Dump in trace view consumes significant memory. If disabled, it will not be loaded by default. The user can always load the dump manually. Dump in already opened trace tabs are not disabled until you close them. + Dump in trace view consumes significant memory. It is used by many features in trace view that need to search for access to memory. If disabled, it will not be loaded by default. The user can always load the dump manually. Dump in already opened trace tabs are not disabled until you close them. Do not automatically load dump in trace view diff --git a/src/gui/Src/Tracer/TraceBrowser.cpp b/src/gui/Src/Tracer/TraceBrowser.cpp index 50a6a83865..50e87feaaf 100644 --- a/src/gui/Src/Tracer/TraceBrowser.cpp +++ b/src/gui/Src/Tracer/TraceBrowser.cpp @@ -14,7 +14,7 @@ #include "MRUList.h" #include -TraceBrowser::TraceBrowser(TraceFileReader* traceFile, QWidget* parent) : AbstractTableView(parent), mTraceFile(traceFile) +TraceBrowser::TraceBrowser(TraceFileReader* traceFile, TraceWidget* parent) : AbstractTableView(parent), mTraceFile(traceFile) { addColumnAt(getCharWidth() * 2 * 2 + 8, tr("Index"), false); //index addColumnAt(getCharWidth() * 2 * sizeof(dsint) + 8, tr("Address"), false); //address @@ -27,6 +27,8 @@ TraceBrowser::TraceBrowser(TraceFileReader* traceFile, QWidget* parent) : Abstra setShowHeader(false); //hide header + mParent = parent; + mSelection.firstSelectedIndex = 0; mSelection.fromIndex = 0; mSelection.toIndex = 0; @@ -870,7 +872,8 @@ void TraceBrowser::setupRightClickContextMenu() return true; }); MenuBuilder* gotoMenu = new MenuBuilder(this, mTraceFileNotNull); - gotoMenu->addAction(makeShortcutAction(DIcon("goto"), tr("Index"), SLOT(gotoSlot()), "ActionGotoExpression"), mTraceFileNotNull); + gotoMenu->addAction(makeShortcutAction(DIcon("geolocation-goto"), tr("Expression"), SLOT(gotoSlot()), "ActionGotoExpression"), mTraceFileNotNull); + gotoMenu->addAction(makeAction(DIcon("goto"), tr("Index"), SLOT(gotoIndexSlot())), mTraceFileNotNull); gotoMenu->addAction(makeAction(DIcon("arrow-step-rtr"), tr("Function return"), SLOT(rtrSlot())), mTraceFileNotNull); gotoMenu->addAction(makeShortcutAction(DIcon("previous"), tr("Previous"), SLOT(gotoPreviousSlot()), "ActionGotoPrevious"), [this](QMenu*) { @@ -1367,7 +1370,50 @@ void TraceBrowser::disasm(unsigned long long index, bool history) emit selectionChanged(getInitialSelection()); } -void TraceBrowser::gotoSlot() +bool TraceBrowser::disasmByAddress(duint address, bool history) +{ + mParent->loadDumpFully(); + auto references = getTraceFile()->getDump()->getReferences(address, address); + unsigned long long index; + bool found = false; + if(references.empty()) + { + return false; + } + else + { + for(auto i : references) + { + if(getTraceFile()->Registers(i).regcontext.cip == address) + { + if(found == false) + { + found = true; + index = i; + } + else + { + // Multiple results, display the Xref dialog + emit xrefSignal(address); + return true; + } + + } + } + if(found) + { + disasm(index, history); + } + else + { + // There is no instruction execution, show the user some other types of memory access + emit xrefSignal(address); + } + return true; + } +} + +void TraceBrowser::gotoIndexSlot() { if(getTraceFile() == nullptr) return; @@ -1380,6 +1426,18 @@ void TraceBrowser::gotoSlot() } } +void TraceBrowser::gotoSlot() +{ + if(getTraceFile() == nullptr) + return; + GotoDialog gotoDlg(this, false, true, true); + if(gotoDlg.exec() == QDialog::Accepted) + { + auto val = DbgValFromString(gotoDlg.expressionText.toUtf8().constData()); + disasmByAddress(val); + } +} + void TraceBrowser::rtrSlot() { // Let's hope this search will be fast... @@ -1816,6 +1874,7 @@ void TraceBrowser::searchMemRefSlot() if(memRefDlg.exec() == QDialog::Accepted) { auto ticks = GetTickCount(); + mParent->loadDumpFully(); int count = TraceFileSearchMemReference(getTraceFile(), memRefDlg.getVal()); GuiShowReferences(); GuiAddLogMessage(tr("%1 result(s) in %2ms\n").arg(count).arg(GetTickCount() - ticks).toUtf8().constData()); diff --git a/src/gui/Src/Tracer/TraceBrowser.h b/src/gui/Src/Tracer/TraceBrowser.h index 6c8d3fda49..553364d08b 100644 --- a/src/gui/Src/Tracer/TraceBrowser.h +++ b/src/gui/Src/Tracer/TraceBrowser.h @@ -5,6 +5,7 @@ #include "QZydis.h" class TraceFileReader; +class TraceWidget; class BreakpointMenu; class CommonActions; @@ -12,7 +13,7 @@ class TraceBrowser : public AbstractTableView { Q_OBJECT public: - explicit TraceBrowser(TraceFileReader* traceFile, QWidget* parent = nullptr); + explicit TraceBrowser(TraceFileReader* traceFile, TraceWidget* parent = nullptr); ~TraceBrowser() override; QString paintContent(QPainter* painter, duint row, duint col, int x, int y, int w, int h) override; @@ -161,6 +162,7 @@ public slots: void selectionChangedSlot(unsigned long long selection); void gotoSlot(); + void gotoIndexSlot(); void rtrSlot(); void gotoPreviousSlot(); void gotoNextSlot(); @@ -188,6 +190,10 @@ public slots: void gotoIndexSlot(duint index); private: + // Go to by index void disasm(unsigned long long index, bool history = true); + // Go to by address, display the Xref dialog if multiple indicies are found + bool disasmByAddress(duint address, bool history = true); + TraceWidget* mParent; }; diff --git a/src/gui/Src/Tracer/TraceFileDump.cpp b/src/gui/Src/Tracer/TraceFileDump.cpp index 087c91fd10..b62e17f125 100644 --- a/src/gui/Src/Tracer/TraceFileDump.cpp +++ b/src/gui/Src/Tracer/TraceFileDump.cpp @@ -22,6 +22,7 @@ void TraceFileDump::clear() unsigned char TraceFileDump::getByte(Key location, bool & success) const { + assert(isEnabled()); auto it = dump.lower_bound(location); success = false; if(it != dump.end()) @@ -54,11 +55,11 @@ unsigned char TraceFileDump::getByte(Key location, bool & success) const } } -std::vector TraceFileDump::getBytes(duint addr, duint size, unsigned long long index) const +void TraceFileDump::getBytes(duint addr, duint size, unsigned long long index, void* buffer) const { - std::vector buffer; + assert(isEnabled()); + unsigned char* ptr = (unsigned char*)buffer; char failedTimes = 0; - buffer.resize(size); for(duint i = 0; i < size; i++) { Key location = {addr + i, index}; @@ -82,7 +83,7 @@ std::vector TraceFileDump::getBytes(duint addr, duint size, unsig { duint gap_size = it->first.addr - location.addr; gap_size = std::min(gap_size, size - i); // prevent overflow - memset(&buffer[i], 0, gap_size); + memset(&ptr[i], 0, gap_size); i += gap_size - 1; continue; } @@ -92,16 +93,16 @@ std::vector TraceFileDump::getBytes(duint addr, duint size, unsig } if(!success) { - buffer[i] = 0; + ptr[i] = 0; continue; } if(location.index > it->first.index) { - buffer[i] = it->second.newData; + ptr[i] = it->second.newData; } else { - buffer[i] = it->second.oldData; // Old data of new instruction is preferred + ptr[i] = it->second.oldData; // Old data of new instruction is preferred } // Peek at next entries to see if we are lucky to have data for addr+i+1 easily, works for data only accessed once while(it != dump.begin() && i + 1 < size && failedTimes < 5) @@ -116,11 +117,11 @@ std::vector TraceFileDump::getBytes(duint addr, duint size, unsig ++i; if(location.index > it->first.index) { - buffer[i] = it->second.newData; + ptr[i] = it->second.newData; } else { - buffer[i] = it->second.oldData; // Old data of new instruction is preferred + ptr[i] = it->second.oldData; // Old data of new instruction is preferred } failedTimes = 0; continue; @@ -132,16 +133,16 @@ std::vector TraceFileDump::getBytes(duint addr, duint size, unsig if(it == dump.begin() && i < size - 1) { // Nothing more, fill the rest with zeros and done - memset(&buffer[i + 1], 0, size - i - 1); + memset(&ptr[i + 1], 0, size - i - 1); break; } } - return buffer; } // find references to the memory address std::vector TraceFileDump::getReferences(duint startAddr, duint endAddr) const { + assert(isEnabled()); std::vector index; if(endAddr < startAddr) std::swap(endAddr, startAddr); @@ -174,6 +175,7 @@ std::vector TraceFileDump::getReferences(duint startAddr, du void TraceFileDump::addMemAccess(duint addr, const void* oldData, const void* newData, size_t size) { + assert(isEnabled()); std::vector> records; records.resize(size); // insert in the correct order @@ -257,8 +259,7 @@ bool TraceFileDumpMemoryPage::read(void* parDest, dsint parRVA, duint parSize) c { if(!dump) return false; - auto buffer = dump->getBytes(mBase + parRVA, parSize, selectedIndex); - memcpy(parDest, buffer.data(), parSize); + dump->getBytes(mBase + parRVA, parSize, selectedIndex, parDest); return true; } diff --git a/src/gui/Src/Tracer/TraceFileDump.h b/src/gui/Src/Tracer/TraceFileDump.h index 23976cd1da..868251ba2d 100644 --- a/src/gui/Src/Tracer/TraceFileDump.h +++ b/src/gui/Src/Tracer/TraceFileDump.h @@ -39,7 +39,7 @@ class TraceFileDump } // Read a byte at "addr" at the moment given in "index" unsigned char getByte(Key location, bool & success) const; - std::vector getBytes(duint addr, duint size, unsigned long long index) const; + void getBytes(duint addr, duint size, unsigned long long index, void* buffer) const; std::vector getReferences(duint startAddr, duint endAddr) const; // Insert a memory access record //void addMemAccess(duint addr, DumpRecord record); diff --git a/src/gui/Src/Tracer/TraceFileSearch.cpp b/src/gui/Src/Tracer/TraceFileSearch.cpp index 295734ddb6..ba6e09612b 100644 --- a/src/gui/Src/Tracer/TraceFileSearch.cpp +++ b/src/gui/Src/Tracer/TraceFileSearch.cpp @@ -98,58 +98,17 @@ int TraceFileSearchMemReference(TraceFileReader* file, duint address) GuiReferenceAddColumn(100, QCoreApplication::translate("TraceFileSearch", "Disassembly").toUtf8().constData()); GuiReferenceAddCommand(QCoreApplication::translate("TraceFileSearch", "Follow index in trace").toUtf8().constData(), "gototrace 0x$1"); GuiReferenceSetRowCount(0); - bool useTraceDump = file->getDump()->isEnabled(); + // We now only support indexed search. So the dump index must be built first. + assert(file->getDump()->isEnabled()); - if(useTraceDump) + if(file->Length() > 0) { - if(file->Length() > 0) - { - file->buildDumpTo(file->Length() - 1); - auto results = file->getReferences(address, address + sizeof(duint) - 1); - for(size_t i = 0; i < results.size(); i++) - { - bool found = false; - unsigned long long index = results[i]; - //Memory - duint memAddr[MAX_MEMORY_OPERANDS]; - duint memOldContent[MAX_MEMORY_OPERANDS]; - duint memNewContent[MAX_MEMORY_OPERANDS]; - bool isValid[MAX_MEMORY_OPERANDS]; - int memAccessCount = file->MemoryAccessCount(index); - if(memAccessCount > 0) - { - file->MemoryAccessInfo(index, memAddr, memOldContent, memNewContent, isValid); - for(int i = 0; i < memAccessCount; i++) - { - found |= inRange(memAddr[i], address, address + sizeof(duint) - 1); - } - //Constants: TO DO - //Populate reference view - if(found) - { - GuiReferenceSetRowCount(count + 1); - GuiReferenceSetCellContent(count, 0, ToPtrString(file->Registers(index).regcontext.cip).toUtf8().constData()); - GuiReferenceSetCellContent(count, 1, file->getIndexText(index).toUtf8().constData()); - unsigned char opcode[16]; - int opcodeSize = 0; - file->OpCode(index, opcode, &opcodeSize); - zy.Disassemble(file->Registers(index).regcontext.cip, opcode, opcodeSize); - GuiReferenceSetCellContent(count, 2, zy.InstructionText(true).c_str()); - //GuiReferenceSetCurrentTaskProgress; GuiReferenceSetProgress - count++; - } - } - } - } - else - count = 0; - return count; - } - else - { - for(unsigned long long index = 0; index < file->Length(); index++) + file->buildDumpTo(file->Length() - 1); + auto results = file->getReferences(address, address + sizeof(duint) - 1); + for(size_t i = 0; i < results.size(); i++) { bool found = false; + unsigned long long index = results[i]; //Memory duint memAddr[MAX_MEMORY_OPERANDS]; duint memOldContent[MAX_MEMORY_OPERANDS]; @@ -181,6 +140,8 @@ int TraceFileSearchMemReference(TraceFileReader* file, duint address) } } } + else + count = 0; return count; } diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index 04e7990d42..ad3284e5f4 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -17,6 +17,7 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q { ui->setupUi(this); + setCursor(QCursor(Qt::CursorShape::WaitCursor)); mTraceFile = new TraceFileReader(this); mTraceFile->Open(fileName); mTraceBrowser = new TraceBrowser(mTraceFile, this); @@ -141,7 +142,7 @@ void TraceWidget::traceSelectionChanged(unsigned long long selection) void TraceWidget::xrefSlot(duint addr) { if(!mDump) - loadDump(); + loadDumpFully(); if(!mXrefDlg) mXrefDlg = new TraceXrefBrowseDialog(this); mXrefDlg->setup(mTraceBrowser->getInitialSelection(), addr, mTraceFile, [this](duint addr) @@ -176,6 +177,7 @@ void TraceWidget::parseFinishedSlot() } mGeneralRegs->setActive(true); } + setCursor(QCursor(Qt::CursorShape::ArrowCursor)); } void TraceWidget::closeFileSlot() @@ -190,10 +192,11 @@ void TraceWidget::displayLogWidgetSlot() void TraceWidget::loadDump() { + assert(!mDump); // Check whether the dump is already loaded mTraceFile->getDump()->setEnabled(); mMemoryPage = new TraceFileDumpMemoryPage(mTraceFile->getDump(), this); auto selection = mTraceBrowser->getInitialSelection(); - mTraceFile->buildDumpTo(selection); // TODO: sometimes this can be slow // TODO: Is it a good idea to build dump index just when opening the file? + mTraceFile->buildDumpTo(selection); // TODO: sometimes this can be slow mMemoryPage->setSelectedIndex(selection); mDump = new TraceDump(mArchitecture, mTraceBrowser, mMemoryPage, this); mStack = new TraceStack(mArchitecture, mTraceBrowser, mMemoryPage, this); @@ -214,6 +217,17 @@ void TraceWidget::loadDump() setupDumpInitialAddresses(selection); } +void TraceWidget::loadDumpFully() +{ + if(mTraceFile->Length() > 0) + { + if(!mTraceFile->getDump()->isEnabled()) + loadDump(); + // Fully build dump index + mTraceFile->buildDumpTo(mTraceFile->Length() - 1); + } +} + void TraceWidget::setupDumpInitialAddresses(unsigned long long selection) { // Setting the initial address of dump view diff --git a/src/gui/Src/Tracer/TraceWidget.h b/src/gui/Src/Tracer/TraceWidget.h index f3964de38c..35457c434e 100644 --- a/src/gui/Src/Tracer/TraceWidget.h +++ b/src/gui/Src/Tracer/TraceWidget.h @@ -29,6 +29,12 @@ class TraceWidget : public QWidget explicit TraceWidget(Architecture* architecture, const QString & fileName, QWidget* parent); ~TraceWidget(); + // Enable trace dump and load it fully before searching + void loadDumpFully(); +public slots: + // Enable trace dump in order to use these features + void loadDump(); + signals: void closeFile(); void displayLogWidget(); @@ -37,7 +43,6 @@ protected slots: void displayLogWidgetSlot(); void traceSelectionChanged(unsigned long long selection); void parseFinishedSlot(); - void loadDump(); void closeFileSlot(); void xrefSlot(duint addr); From c1c7608fabc5329f6e1854ac12d53083aa868b32 Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Sat, 13 Jul 2024 20:52:53 +0800 Subject: [PATCH 31/33] Include assert.h --- src/gui/Src/Tracer/TraceFileDump.cpp | 1 + src/gui/Src/Tracer/TraceFileSearch.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/src/gui/Src/Tracer/TraceFileDump.cpp b/src/gui/Src/Tracer/TraceFileDump.cpp index b62e17f125..f09b03ae98 100644 --- a/src/gui/Src/Tracer/TraceFileDump.cpp +++ b/src/gui/Src/Tracer/TraceFileDump.cpp @@ -1,3 +1,4 @@ +#include #include #include "Configuration.h" #include "TraceFileDump.h" diff --git a/src/gui/Src/Tracer/TraceFileSearch.cpp b/src/gui/Src/Tracer/TraceFileSearch.cpp index ba6e09612b..cf672535a9 100644 --- a/src/gui/Src/Tracer/TraceFileSearch.cpp +++ b/src/gui/Src/Tracer/TraceFileSearch.cpp @@ -1,3 +1,4 @@ +#include #include #include "TraceFileReader.h" #include "TraceFileSearch.h" From 4119b0fc29c62ce6d80e218afe28111a2d73b12e Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Wed, 17 Jul 2024 21:13:54 +0800 Subject: [PATCH 32/33] Fix trace not showing registers and following in disasm/stack from stack --- src/gui/Src/Tracer/TraceBrowser.cpp | 30 +++++++- src/gui/Src/Tracer/TraceBrowser.h | 3 +- src/gui/Src/Tracer/TraceFileDump.cpp | 30 ++------ src/gui/Src/Tracer/TraceFileDump.h | 3 +- src/gui/Src/Tracer/TraceStack.cpp | 109 ++++++++++++++------------- src/gui/Src/Tracer/TraceStack.h | 5 +- src/gui/Src/Tracer/TraceWidget.cpp | 8 +- src/gui/Src/Tracer/TraceWidget.h | 1 + 8 files changed, 101 insertions(+), 88 deletions(-) diff --git a/src/gui/Src/Tracer/TraceBrowser.cpp b/src/gui/Src/Tracer/TraceBrowser.cpp index 50e87feaaf..695c2f4e73 100644 --- a/src/gui/Src/Tracer/TraceBrowser.cpp +++ b/src/gui/Src/Tracer/TraceBrowser.cpp @@ -1370,7 +1370,7 @@ void TraceBrowser::disasm(unsigned long long index, bool history) emit selectionChanged(getInitialSelection()); } -bool TraceBrowser::disasmByAddress(duint address, bool history) +void TraceBrowser::disasmByAddress(duint address, bool history) { mParent->loadDumpFully(); auto references = getTraceFile()->getDump()->getReferences(address, address); @@ -1378,7 +1378,25 @@ bool TraceBrowser::disasmByAddress(duint address, bool history) bool found = false; if(references.empty()) { - return false; + QString addr = ToPtrString(address); + QMessageBox msg(this); + msg.setIcon(QMessageBox::Warning); + msg.setWindowTitle(tr("Address not found in trace")); + if(DbgIsDebugging()) + { + msg.setText(tr("The address %1 is not found in trace.").arg(addr) + ' ' + tr("Do you want to follow in CPU instead?")); + msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No); + if(msg.exec() == QMessageBox::Yes) + { + DbgCmdExec(QString("disasm %1").arg(addr)); + } + } + else + { + msg.setText(tr("The address %1 is not found in trace.").arg(addr)); + msg.setStandardButtons(QMessageBox::Ok); + msg.exec(); + } } else { @@ -1395,7 +1413,7 @@ bool TraceBrowser::disasmByAddress(duint address, bool history) { // Multiple results, display the Xref dialog emit xrefSignal(address); - return true; + return; } } @@ -1409,7 +1427,6 @@ bool TraceBrowser::disasmByAddress(duint address, bool history) // There is no instruction execution, show the user some other types of memory access emit xrefSignal(address); } - return true; } } @@ -1907,3 +1924,8 @@ void TraceBrowser::gotoIndexSlot(duint index) { disasm(index, false); } + +void TraceBrowser::gotoAddressSlot(duint address) +{ + disasmByAddress(address, false); +} diff --git a/src/gui/Src/Tracer/TraceBrowser.h b/src/gui/Src/Tracer/TraceBrowser.h index 553364d08b..4313edd00c 100644 --- a/src/gui/Src/Tracer/TraceBrowser.h +++ b/src/gui/Src/Tracer/TraceBrowser.h @@ -188,12 +188,13 @@ public slots: void synchronizeCpuSlot(); void gotoIndexSlot(duint index); + void gotoAddressSlot(duint index); private: // Go to by index void disasm(unsigned long long index, bool history = true); // Go to by address, display the Xref dialog if multiple indicies are found - bool disasmByAddress(duint address, bool history = true); + void disasmByAddress(duint address, bool history = true); TraceWidget* mParent; }; diff --git a/src/gui/Src/Tracer/TraceFileDump.cpp b/src/gui/Src/Tracer/TraceFileDump.cpp index f09b03ae98..f9c419841e 100644 --- a/src/gui/Src/Tracer/TraceFileDump.cpp +++ b/src/gui/Src/Tracer/TraceFileDump.cpp @@ -21,39 +21,19 @@ void TraceFileDump::clear() dump.clear(); } -unsigned char TraceFileDump::getByte(Key location, bool & success) const +bool TraceFileDump::isValidReadPtr(duint address) const { assert(isEnabled()); + Key location = {address, maxIndex + 1}; auto it = dump.lower_bound(location); - success = false; if(it != dump.end()) { - if(it->first.addr == location.addr) + if(it->first.addr == address) { - success = true; + return true; } - else if(it != dump.begin()) - { - // try to get to next record which may hold the required data - --it; - if(it->first.addr == location.addr) - { - success = true; - } - } - } - if(!success) - { - return 0; - } - if(location.index > it->first.index) - { - return it->second.newData; - } - else - { - return it->second.oldData; } + return false; } void TraceFileDump::getBytes(duint addr, duint size, unsigned long long index, void* buffer) const diff --git a/src/gui/Src/Tracer/TraceFileDump.h b/src/gui/Src/Tracer/TraceFileDump.h index 868251ba2d..01a1e555cd 100644 --- a/src/gui/Src/Tracer/TraceFileDump.h +++ b/src/gui/Src/Tracer/TraceFileDump.h @@ -38,7 +38,7 @@ class TraceFileDump return enabled; } // Read a byte at "addr" at the moment given in "index" - unsigned char getByte(Key location, bool & success) const; + bool isValidReadPtr(duint addr) const; void getBytes(duint addr, duint size, unsigned long long index, void* buffer) const; std::vector getReferences(duint startAddr, duint endAddr) const; // Insert a memory access record @@ -57,6 +57,7 @@ class TraceFileDump std::vector> memAreas; private: std::map dump; + // maxIndex is the last index included here. As the debuggee steps there will be new data coming. unsigned long long maxIndex; bool enabled; }; diff --git a/src/gui/Src/Tracer/TraceStack.cpp b/src/gui/Src/Tracer/TraceStack.cpp index 4fc7738452..13904b686a 100644 --- a/src/gui/Src/Tracer/TraceStack.cpp +++ b/src/gui/Src/Tracer/TraceStack.cpp @@ -14,7 +14,7 @@ #include "GotoDialog.h" TraceStack::TraceStack(Architecture* architecture, TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent) - : mMemoryPage(memoryPage), mDisas(disas), HexDump(architecture, parent, memoryPage) + : HexDump(architecture, parent, memoryPage), mDisas(disas) { setWindowTitle("Stack"); setDrawDebugOnly(false); @@ -50,7 +50,7 @@ TraceStack::TraceStack(Architecture* architecture, TraceBrowser* disas, TraceFil mGoto = 0; // Slots - //connect(this, SIGNAL(selectionUpdated()), this, SLOT(selectionUpdatedSlot())); + connect(this, SIGNAL(selectionUpdated()), this, SLOT(selectionUpdatedSlot())); Initialize(); } @@ -78,7 +78,7 @@ void TraceStack::setupContextMenu() { mMenuBuilder = new MenuBuilder(this, [this](QMenu*) { - return mMemoryPage->isAvailable(); + return static_cast(mMemPage)->isAvailable(); }); mCommonActions = new CommonActions(this, getActionHelperFuncs(), [this]() { @@ -144,29 +144,33 @@ void TraceStack::setupContextMenu() //mCommonActions->build(mMenuBuilder, CommonActions::ActionMemoryMap | CommonActions::ActionDump | CommonActions::ActionDumpData); //Follow in Stack - //auto followStackName = ArchValue(tr("Follow DWORD in &Stack"), tr("Follow QWORD in &Stack")); - //mFollowStack = makeAction(DIcon("stack"), followStackName, SLOT(followStackSlot())); - //mFollowStack->setShortcutContext(Qt::WidgetShortcut); + auto followStackName = ArchValue(tr("Follow DWORD in &Stack"), tr("Follow QWORD in &Stack")); + mFollowStack = makeAction(DIcon("stack"), followStackName, SLOT(followStackSlot())); + mFollowStack->setShortcutContext(Qt::WidgetShortcut); //mFollowStack->setShortcut(QKeySequence("enter")); - //mMenuBuilder->addAction(mFollowStack, [this](QMenu*) - //{ - // duint ptr; - // if(!DbgMemRead(rvaToVa(getInitialSelection()), (unsigned char*)&ptr, sizeof(ptr))) - // return false; - // duint stackBegin = mMemPage->getBase(); - // duint stackEnd = stackBegin + mMemPage->getSize(); - // return ptr >= stackBegin && ptr < stackEnd; - //}); + mMenuBuilder->addAction(mFollowStack, [this](QMenu*) + { + duint ptr; + if(!mMemPage->read(&ptr, getInitialSelection(), sizeof(ptr))) + return false; + duint stackBegin = mMemPage->getBase(); + duint stackEnd = stackBegin + mMemPage->getSize(); + return ptr >= stackBegin && ptr < stackEnd; + }); //Follow in Disassembler auto disasmIcon = DIcon(ArchValue("processor32", "processor64")); mFollowDisasm = makeAction(disasmIcon, ArchValue(tr("&Follow DWORD in Disassembler"), tr("&Follow QWORD in Disassembler")), SLOT(followDisasmSlot())); mFollowDisasm->setShortcutContext(Qt::WidgetShortcut); - mFollowDisasm->setShortcut(QKeySequence("enter")); + //mFollowDisasm->setShortcut(QKeySequence("enter")); mMenuBuilder->addAction(mFollowDisasm, [this](QMenu*) { duint ptr; - return DbgMemRead(rvaToVa(getInitialSelection()), (unsigned char*)&ptr, sizeof(ptr)) && DbgMemIsValidReadPtr(ptr); + if(!mMemPage->read(&ptr, getInitialSelection(), sizeof(ptr))) + return false; + if(mDisas->getTraceFile()->getDump()->isValidReadPtr(ptr)) + return true; + return false; }); mMenuBuilder->addAction(makeAction("Edit columns...", SLOT(editColumnDialog()))); @@ -363,7 +367,7 @@ void TraceStack::wheelEvent(QWheelEvent* event) void TraceStack::stackDumpAt(duint addr, duint csp) { - if(DbgMemIsValidReadPtr(addr)) + if(mDisas->getTraceFile()->getDump()->isValidReadPtr(addr)) mHistory.addVaToHistory(addr); mCsp = csp; @@ -432,12 +436,12 @@ void TraceStack::printDumpAt(duint parVA, bool select, bool repaint, bool update // Modified from Hexdump, removed memory page information // TODO: get memory range from trace instead const duint wSize = 0x1000; // TODO: Using 4KB pages currently - auto wBase = mMemoryPage->getBase(); + auto wBase = mMemPage->getBase(); dsint wRVA = parVA - wBase; //calculate rva if(wRVA < 0 || wRVA >= wSize) { wBase = parVA & ~(wSize - 1); - mMemoryPage->setAttributes(wBase, wSize); + mMemPage->setAttributes(wBase, wSize); wRVA = parVA - wBase; //calculate rva } int wBytePerRowCount = getBytePerRowCount(); //get the number of bytes per row @@ -473,6 +477,7 @@ void TraceStack::printDumpAt(duint parVA, bool select, bool repaint, bool update reloadData(); } +/* void TraceStack::disasmSelectionChanged(duint parVA) { // When the selected instruction is changed, select the argument that is in the stack. @@ -514,7 +519,7 @@ void TraceStack::disasmSelectionChanged(duint parVA) mUnderlineRangeEndVa = underlineEnd; reloadData(); } -} +}*/ // TODO void TraceStack::gotoCspSlot() @@ -530,7 +535,7 @@ void TraceStack::gotoCbpSlot() void TraceStack::gotoExpressionSlot() { - if(!mMemoryPage->isAvailable()) + if(!static_cast(mMemPage)->isAvailable()) return; if(!mGoto) mGoto = new GotoDialog(this, false, true, true); @@ -544,40 +549,42 @@ void TraceStack::gotoExpressionSlot() } } -//void TraceStack::selectionUpdatedSlot() -//{ -// duint selectedData; -// if(mMemPage->read((byte_t*)&selectedData, getInitialSelection(), sizeof(duint))) -// if(DbgMemIsValidReadPtr(selectedData)) //data is a pointer -// { -// duint stackBegin = mMemPage->getBase(); -// duint stackEnd = stackBegin + mMemPage->getSize(); -// if(selectedData >= stackBegin && selectedData < stackEnd) //data is a pointer to stack address -// { -// disconnect(SIGNAL(enterPressedSignal())); -// connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followStackSlot())); -// mFollowDisasm->setShortcut(QKeySequence("")); -// mFollowStack->setShortcut(QKeySequence("enter")); -// } -// else -// { -// disconnect(SIGNAL(enterPressedSignal())); -// connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followDisasmSlot())); -// mFollowStack->setShortcut(QKeySequence("")); -// mFollowDisasm->setShortcut(QKeySequence("enter")); -// } -// } -//} - -void TraceStack::followDisasmSlot() +void TraceStack::selectionUpdatedSlot() { duint selectedData; if(mMemPage->read((byte_t*)&selectedData, getInitialSelection(), sizeof(duint))) - if(DbgMemIsValidReadPtr(selectedData)) //data is a pointer + { + if(mDisas->getTraceFile()->getDump()->isValidReadPtr(selectedData)) //data is a pointer { - QString addrText = ToPtrString(selectedData); - DbgCmdExec(QString("disasm " + addrText)); + duint stackBegin = mMemPage->getBase(); + duint stackEnd = stackBegin + mMemPage->getSize(); + if(selectedData >= stackBegin && selectedData < stackEnd) //data is a pointer to stack address + { + disconnect(SIGNAL(enterPressedSignal())); + connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followStackSlot())); + mFollowDisasm->setShortcut(QKeySequence("")); + mFollowStack->setShortcut(QKeySequence("enter")); + } + else + { + disconnect(SIGNAL(enterPressedSignal())); + connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followDisasmSlot())); + mFollowStack->setShortcut(QKeySequence("")); + mFollowDisasm->setShortcut(QKeySequence("enter")); + } + } + else + { + disconnect(SIGNAL(enterPressedSignal())); } + } +} + +void TraceStack::followDisasmSlot() +{ + duint selectedData; + if(mMemPage->read((byte_t*)&selectedData, getInitialSelection(), sizeof(duint))) + mDisas->gotoAddressSlot(selectedData); } void TraceStack::followStackSlot() diff --git a/src/gui/Src/Tracer/TraceStack.h b/src/gui/Src/Tracer/TraceStack.h index 5460fc1934..a3024c4742 100644 --- a/src/gui/Src/Tracer/TraceStack.h +++ b/src/gui/Src/Tracer/TraceStack.h @@ -39,18 +39,17 @@ public slots: void gotoCbpSlot(); void gotoExpressionSlot(); void gotoXrefSlot(); - //void selectionUpdatedSlot(); + void selectionUpdatedSlot(); void followDisasmSlot(); void followStackSlot(); void binaryCopySlot(); //void freezeStackSlot(); - void disasmSelectionChanged(duint parVA); + //void disasmSelectionChanged(duint parVA); void updateSlot(); void copyPtrColumnSlot(); void copyCommentsColumnSlot(); private: - TraceFileDumpMemoryPage* mMemoryPage; TraceBrowser* mDisas; duint mCsp = 0; diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index ad3284e5f4..2778d21a2d 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -136,6 +136,8 @@ void TraceWidget::traceSelectionChanged(unsigned long long selection) else memset(®isters, 0, sizeof(registers)); } + else + memset(®isters, 0, sizeof(registers)); mGeneralRegs->setRegisters(®isters); } @@ -154,12 +156,13 @@ void TraceWidget::xrefSlot(duint addr) void TraceWidget::parseFinishedSlot() { - duint initialAddress; QString reason; + setCursor(QCursor(Qt::CursorShape::ArrowCursor)); if(mTraceFile->isError(reason)) { SimpleErrorBox(this, tr("Error"), tr("Error when opening trace recording (reason: %1)").arg(reason)); emit closeFile(); + return; } else if(mTraceFile->Length() > 0) { @@ -175,9 +178,8 @@ void TraceWidget::parseFinishedSlot() { setupDumpInitialAddresses(0); } - mGeneralRegs->setActive(true); } - setCursor(QCursor(Qt::CursorShape::ArrowCursor)); + mGeneralRegs->setActive(true); } void TraceWidget::closeFileSlot() diff --git a/src/gui/Src/Tracer/TraceWidget.h b/src/gui/Src/Tracer/TraceWidget.h index 35457c434e..93a05680f8 100644 --- a/src/gui/Src/Tracer/TraceWidget.h +++ b/src/gui/Src/Tracer/TraceWidget.h @@ -55,6 +55,7 @@ protected slots: TraceFileDumpMemoryPage* mMemoryPage; TraceStack* mStack; TraceXrefBrowseDialog* mXrefDlg; + QPushButton* mLoadDump; Architecture* mArchitecture; From 498e072239fb45411ab1bc8fa861f9d4a59582bc Mon Sep 17 00:00:00 2001 From: torusrxxx Date: Fri, 19 Jul 2024 18:49:13 +0800 Subject: [PATCH 33/33] Add follow in dump in trace infobox --- src/gui/Src/Gui/CPUInfoBox.cpp | 2 +- src/gui/Src/Tracer/TraceDump.cpp | 5 +- src/gui/Src/Tracer/TraceDump.h | 7 +- src/gui/Src/Tracer/TraceInfoBox.cpp | 129 +++++++++++++++++++++++++++- src/gui/Src/Tracer/TraceInfoBox.h | 5 ++ src/gui/Src/Tracer/TraceStack.cpp | 19 ++-- src/gui/Src/Tracer/TraceStack.h | 5 +- src/gui/Src/Tracer/TraceWidget.cpp | 8 +- src/gui/Src/Tracer/TraceWidget.h | 16 ++++ 9 files changed, 174 insertions(+), 22 deletions(-) diff --git a/src/gui/Src/Gui/CPUInfoBox.cpp b/src/gui/Src/Gui/CPUInfoBox.cpp index aa5cdb0fd1..ae24f2b67b 100644 --- a/src/gui/Src/Gui/CPUInfoBox.cpp +++ b/src/gui/Src/Gui/CPUInfoBox.cpp @@ -709,7 +709,7 @@ void CPUInfoBox::addWatchMenuItem(QMenu* menu, QString name, duint value) } /** - * @brief CPUInfoBox::setupFollowMenu Set up a follow menu. + * @brief CPUInfoBox::setupWatchMenu Set up a watch menu. * @param menu The menu to create * @param va The selected VA */ diff --git a/src/gui/Src/Tracer/TraceDump.cpp b/src/gui/Src/Tracer/TraceDump.cpp index 8635e6011b..efb438571a 100644 --- a/src/gui/Src/Tracer/TraceDump.cpp +++ b/src/gui/Src/Tracer/TraceDump.cpp @@ -1,4 +1,5 @@ #include "TraceDump.h" +#include "TraceWidget.h" #include "TraceFileReader.h" #include "TraceFileDump.h" #include @@ -15,9 +16,9 @@ #include "MiscUtil.h" #include "BackgroundFlickerThread.h" -TraceDump::TraceDump(Architecture* architecture, TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent) : mMemoryPage(memoryPage), HexDump(architecture, parent, memoryPage) +TraceDump::TraceDump(Architecture* architecture, TraceWidget* parent, TraceFileDumpMemoryPage* memoryPage) : mMemoryPage(memoryPage), HexDump(architecture, parent, memoryPage) { - mDisas = disas; + mParent = parent; setDrawDebugOnly(false); //mMultiDump = multiDump; diff --git a/src/gui/Src/Tracer/TraceDump.h b/src/gui/Src/Tracer/TraceDump.h index d91b73a610..02428f93c8 100644 --- a/src/gui/Src/Tracer/TraceDump.h +++ b/src/gui/Src/Tracer/TraceDump.h @@ -4,7 +4,8 @@ #include "TraceFileDump.h" //forward declaration -//class CPUMultiDump; +// TODO: multiple dumps +class TraceWidget; class TraceBrowser; class GotoDialog; class CommonActions; @@ -13,7 +14,7 @@ class TraceDump : public HexDump { Q_OBJECT public: - explicit TraceDump(Architecture* architecture, TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent); + explicit TraceDump(Architecture* architecture, TraceWidget* parent, TraceFileDumpMemoryPage* memoryPage); ~TraceDump(); void getColumnRichText(duint col, duint rva, RichTextPainter::List & richText) override; QString paintContent(QPainter* painter, duint row, duint col, int x, int y, int w, int h) override; @@ -95,7 +96,7 @@ public slots: GotoDialog* mGoto = nullptr; GotoDialog* mGotoOffset = nullptr; - TraceBrowser* mDisas; + TraceWidget* mParent; //CPUMultiDump* mMultiDump; int mAsciiSeparator = 0; diff --git a/src/gui/Src/Tracer/TraceInfoBox.cpp b/src/gui/Src/Tracer/TraceInfoBox.cpp index b3de15e2b2..002bd91494 100644 --- a/src/gui/Src/Tracer/TraceInfoBox.cpp +++ b/src/gui/Src/Tracer/TraceInfoBox.cpp @@ -1,10 +1,12 @@ #include "TraceInfoBox.h" #include "TraceWidget.h" +#include "TraceDump.h" +#include "TraceBrowser.h" #include "TraceFileReader.h" #include "CPUInfoBox.h" #include "zydis_wrapper.h" -TraceInfoBox::TraceInfoBox(TraceWidget* parent) : StdTable(parent) +TraceInfoBox::TraceInfoBox(TraceWidget* parent) : StdTable(parent), mParent(parent) { setWindowTitle("TraceInfoBox"); enableMultiSelection(false); @@ -23,6 +25,7 @@ TraceInfoBox::TraceInfoBox(TraceWidget* parent) : StdTable(parent) setMinimumHeight((getRowHeight() + 1) * 4); connect(this, SIGNAL(contextMenuSignal(QPoint)), this, SLOT(contextMenuSlot(QPoint))); + mCurAddr = 0; // Deselect any row (visual reasons only) setSingleSelection(-1); @@ -50,7 +53,8 @@ void TraceInfoBox::update(unsigned long long selection, TraceFileReader* traceFi MemoryOperandsCount = traceFile->MemoryAccessCount(selection); if(MemoryOperandsCount > 0) traceFile->MemoryAccessInfo(selection, MemoryAddress, MemoryOldContent, MemoryNewContent, MemoryIsValid); - if(zydis.Disassemble(registers.regcontext.cip, opcode, opsize)) + mCurAddr = registers.regcontext.cip; + if(zydis.Disassemble(mCurAddr, opcode, opsize)) { uint8_t opindex; int memaccessindex; @@ -230,15 +234,136 @@ int TraceInfoBox::getHeight() return ((getRowHeight() + 1) * 4); } +/** + * @brief TraceInfoBox::addFollowMenuItem Add a follow action to the menu + * @param menu The menu to which the follow action adds + * @param name The user-friendly name of the action + * @param value The VA of the address + */ +void TraceInfoBox::addFollowMenuItem(QMenu* menu, QString name, duint value) +{ + foreach(QAction* action, menu->actions()) //check for duplicate action + if(action->text() == name) + return; + QAction* newAction = new QAction(name, menu); + menu->addAction(newAction); + newAction->setObjectName(ToPtrString(value)); + connect(newAction, SIGNAL(triggered()), this, SLOT(followActionSlot())); +} + +/** + * @brief TraceInfoBox::setupFollowMenu Set up a follow menu. + * @param menu The menu to create + * @param va The selected VA + */ +void TraceInfoBox::setupFollowMenu(QMenu* menu, duint va) +{ + //most basic follow action + addFollowMenuItem(menu, tr("&Selected Address"), va); + + //add follow actions + mParent->loadDumpFully(); + TraceFileReader* traceFile = mParent->getTraceFile(); + TraceFileDump* traceDump = traceFile->getDump(); + duint selection = mParent->getTraceBrowser()->getInitialSelection(); + Zydis zydis; + unsigned char opcode[16]; + int opsize; + traceFile->OpCode(selection, opcode, &opsize); + duint MemoryAddress[MAX_MEMORY_OPERANDS]; + duint MemoryOldContent[MAX_MEMORY_OPERANDS]; + duint MemoryNewContent[MAX_MEMORY_OPERANDS]; + bool MemoryIsValid[MAX_MEMORY_OPERANDS]; + int MemoryOperandsCount; + MemoryOperandsCount = traceFile->MemoryAccessCount(selection); + if(MemoryOperandsCount > 0) + traceFile->MemoryAccessInfo(selection, MemoryAddress, MemoryOldContent, MemoryNewContent, MemoryIsValid); + REGDUMP registers = traceFile->Registers(selection); + if(zydis.Disassemble(mCurAddr, opcode, opsize)) + { + for(uint8_t opindex = 0; opindex < zydis.OpCount(); opindex++) + { + size_t value = zydis.ResolveOpValue(opindex, [®isters](ZydisRegister reg) + { + return resolveZydisRegister(registers, reg); + }); + + if(zydis[opindex].type == ZYDIS_OPERAND_TYPE_MEMORY) + { + if(zydis[opindex].size == sizeof(void*) * 8) + { + if(traceDump->isValidReadPtr(value)) + { + addFollowMenuItem(menu, tr("&Address: ") + QString::fromStdString(zydis.OperandText(opindex)), value); + } + for(uint8_t memaccessindex = 0; memaccessindex < MemoryOperandsCount; memaccessindex++) + { + if(MemoryAddress[memaccessindex] == value) + { + if(traceDump->isValidReadPtr(MemoryOldContent[memaccessindex])) + { + if(MemoryOldContent[memaccessindex] != MemoryNewContent[memaccessindex]) + { + addFollowMenuItem(menu, tr("&Old value: ") + ToPtrString(MemoryOldContent[memaccessindex]), MemoryOldContent[memaccessindex]); + } + else + { + addFollowMenuItem(menu, tr("&Value: ") + ToPtrString(MemoryOldContent[memaccessindex]), MemoryOldContent[memaccessindex]); + break; + } + } + if(traceDump->isValidReadPtr(MemoryNewContent[memaccessindex])) + { + addFollowMenuItem(menu, tr("&New value: ") + ToPtrString(MemoryNewContent[memaccessindex]), MemoryNewContent[memaccessindex]); + } + break; + } + } + } + } + else if(zydis[opindex].type == ZYDIS_OPERAND_TYPE_IMMEDIATE) + { + if(traceDump->isValidReadPtr(value)) + { + addFollowMenuItem(menu, tr("&Constant: ") + QString::fromStdString(zydis.OperandText(opindex)), value); + } + } + } + } +} + void TraceInfoBox::contextMenuSlot(QPoint pos) { QMenu menu(this); //create context menu + QMenu followMenu(tr("&Follow in Dump"), this); + followMenu.setIcon(DIcon("dump")); + connect(&followMenu, &QMenu::aboutToShow, [&followMenu, this]() + { + // The following method will load dump, so we postpone until the mouse hovers it. + setupFollowMenu(&followMenu, mCurAddr); + }); + menu.addMenu(&followMenu); QMenu copyMenu(tr("&Copy"), this); setupCopyMenu(©Menu); menu.addMenu(©Menu); menu.exec(mapToGlobal(pos)); //execute context menu } +/** + * @brief TraceInfoBox::followActionSlot Called when follow action is clicked + */ +void TraceInfoBox::followActionSlot() +{ + QAction* action = qobject_cast(sender()); + duint data; +#ifdef _WIN64 + data = action->objectName().toULongLong(nullptr, 16); +#else + data = action->objectName().toULong(nullptr, 16); +#endif //_WIN64 + mParent->getTraceDump()->printDumpAt(data, true, true, true); +} + void TraceInfoBox::setupShortcuts() { mCopyLineAction->setShortcut(ConfigShortcut("ActionCopyLine")); diff --git a/src/gui/Src/Tracer/TraceInfoBox.h b/src/gui/Src/Tracer/TraceInfoBox.h index 1391f7883f..932539baf8 100644 --- a/src/gui/Src/Tracer/TraceInfoBox.h +++ b/src/gui/Src/Tracer/TraceInfoBox.h @@ -11,6 +11,8 @@ class TraceInfoBox : public StdTable public: TraceInfoBox(TraceWidget* parent); int getHeight(); + void setupFollowMenu(QMenu* menu, duint va); + void addFollowMenuItem(QMenu* menu, QString name, duint value); ~TraceInfoBox(); void update(unsigned long long selection, TraceFileReader* traceFile, const REGDUMP & registers); @@ -18,10 +20,13 @@ class TraceInfoBox : public StdTable public slots: void contextMenuSlot(QPoint pos); + void followActionSlot(); private: void setupContextMenu(); void setupShortcuts(); QAction* mCopyLineAction; + TraceWidget* mParent; + duint mCurAddr; }; diff --git a/src/gui/Src/Tracer/TraceStack.cpp b/src/gui/Src/Tracer/TraceStack.cpp index 13904b686a..a89d9476b4 100644 --- a/src/gui/Src/Tracer/TraceStack.cpp +++ b/src/gui/Src/Tracer/TraceStack.cpp @@ -1,3 +1,4 @@ +#include "TraceWidget.h" #include "TraceStack.h" #include "TraceDump.h" #include "TraceFileReader.h" @@ -13,9 +14,11 @@ #include "CPUMultiDump.h" #include "GotoDialog.h" -TraceStack::TraceStack(Architecture* architecture, TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent) - : HexDump(architecture, parent, memoryPage), mDisas(disas) +TraceStack::TraceStack(Architecture* architecture, TraceWidget* parent, TraceFileDumpMemoryPage* memoryPage) + : HexDump(architecture, parent, memoryPage) { + mParent = parent; + setWindowTitle("Stack"); setDrawDebugOnly(false); setShowHeader(false); @@ -168,7 +171,7 @@ void TraceStack::setupContextMenu() duint ptr; if(!mMemPage->read(&ptr, getInitialSelection(), sizeof(ptr))) return false; - if(mDisas->getTraceFile()->getDump()->isValidReadPtr(ptr)) + if(mParent->getTraceFile()->getDump()->isValidReadPtr(ptr)) return true; return false; }); @@ -247,7 +250,7 @@ void TraceStack::getColumnRichText(duint col, duint rva, RichTextPainter::List & void TraceStack::reloadData() { - mCsp = mDisas->getTraceFile()->Registers(mDisas->getInitialSelection()).regcontext.csp; + mCsp = mParent->getTraceFile()->Registers(mParent->getTraceBrowser()->getInitialSelection()).regcontext.csp; HexDump::reloadData(); } @@ -367,7 +370,7 @@ void TraceStack::wheelEvent(QWheelEvent* event) void TraceStack::stackDumpAt(duint addr, duint csp) { - if(mDisas->getTraceFile()->getDump()->isValidReadPtr(addr)) + if(mParent->getTraceFile()->getDump()->isValidReadPtr(addr)) mHistory.addVaToHistory(addr); mCsp = csp; @@ -530,7 +533,7 @@ void TraceStack::gotoCspSlot() void TraceStack::gotoCbpSlot() { - stackDumpAt(mDisas->getTraceFile()->Registers(mDisas->getInitialSelection()).regcontext.cbp, mCsp); + stackDumpAt(mParent->getTraceFile()->Registers(mParent->getTraceBrowser()->getInitialSelection()).regcontext.cbp, mCsp); } void TraceStack::gotoExpressionSlot() @@ -554,7 +557,7 @@ void TraceStack::selectionUpdatedSlot() duint selectedData; if(mMemPage->read((byte_t*)&selectedData, getInitialSelection(), sizeof(duint))) { - if(mDisas->getTraceFile()->getDump()->isValidReadPtr(selectedData)) //data is a pointer + if(mParent->getTraceFile()->getDump()->isValidReadPtr(selectedData)) //data is a pointer { duint stackBegin = mMemPage->getBase(); duint stackEnd = stackBegin + mMemPage->getSize(); @@ -584,7 +587,7 @@ void TraceStack::followDisasmSlot() { duint selectedData; if(mMemPage->read((byte_t*)&selectedData, getInitialSelection(), sizeof(duint))) - mDisas->gotoAddressSlot(selectedData); + mParent->getTraceBrowser()->gotoAddressSlot(selectedData); } void TraceStack::followStackSlot() diff --git a/src/gui/Src/Tracer/TraceStack.h b/src/gui/Src/Tracer/TraceStack.h index a3024c4742..677abfa8b7 100644 --- a/src/gui/Src/Tracer/TraceStack.h +++ b/src/gui/Src/Tracer/TraceStack.h @@ -6,6 +6,7 @@ class CPUMultiDump; class GotoDialog; class CommonActions; +class TraceWidget; class TraceBrowser; class TraceFileDumpMemoryPage; @@ -13,7 +14,7 @@ class TraceStack : public HexDump { Q_OBJECT public: - explicit TraceStack(Architecture* architecture, TraceBrowser* disas, TraceFileDumpMemoryPage* memoryPage, QWidget* parent = nullptr); + explicit TraceStack(Architecture* architecture, TraceWidget* parent, TraceFileDumpMemoryPage* memoryPage); // Configuration void updateColors() override; @@ -50,7 +51,7 @@ public slots: void copyCommentsColumnSlot(); private: - TraceBrowser* mDisas; + TraceWidget* mParent; duint mCsp = 0; bool bStackFrozen = false; diff --git a/src/gui/Src/Tracer/TraceWidget.cpp b/src/gui/Src/Tracer/TraceWidget.cpp index 2778d21a2d..cde7b19a13 100644 --- a/src/gui/Src/Tracer/TraceWidget.cpp +++ b/src/gui/Src/Tracer/TraceWidget.cpp @@ -27,8 +27,8 @@ TraceWidget::TraceWidget(Architecture* architecture, const QString & fileName, Q { mTraceFile->getDump()->setEnabled(); mMemoryPage = new TraceFileDumpMemoryPage(mTraceFile->getDump(), this); - mDump = new TraceDump(architecture, mTraceBrowser, mMemoryPage, this); - mStack = new TraceStack(architecture, mTraceBrowser, mMemoryPage, this); + mDump = new TraceDump(architecture, this, mMemoryPage); + mStack = new TraceStack(architecture, this, mMemoryPage); mLoadDump = nullptr; } else @@ -200,8 +200,8 @@ void TraceWidget::loadDump() auto selection = mTraceBrowser->getInitialSelection(); mTraceFile->buildDumpTo(selection); // TODO: sometimes this can be slow mMemoryPage->setSelectedIndex(selection); - mDump = new TraceDump(mArchitecture, mTraceBrowser, mMemoryPage, this); - mStack = new TraceStack(mArchitecture, mTraceBrowser, mMemoryPage, this); + mDump = new TraceDump(mArchitecture, this, mMemoryPage); + mStack = new TraceStack(mArchitecture, this, mMemoryPage); //dump ui->mBotLeftFrameLayout->removeWidget(mLoadDump); diff --git a/src/gui/Src/Tracer/TraceWidget.h b/src/gui/Src/Tracer/TraceWidget.h index 93a05680f8..eff1c6a1f1 100644 --- a/src/gui/Src/Tracer/TraceWidget.h +++ b/src/gui/Src/Tracer/TraceWidget.h @@ -29,6 +29,22 @@ class TraceWidget : public QWidget explicit TraceWidget(Architecture* architecture, const QString & fileName, QWidget* parent); ~TraceWidget(); + inline TraceFileReader* getTraceFile() const + { + return mTraceFile; + }; + inline TraceBrowser* getTraceBrowser() const + { + return mTraceBrowser; + }; + inline TraceDump* getTraceDump() const + { + return mDump; + }; + inline TraceStack* getTraceStack() const + { + return mStack; + }; // Enable trace dump and load it fully before searching void loadDumpFully(); public slots: