Merge pull request #3405 from torusrxxx/patch000000fb

Use 32-bit trace index to save memory
This commit is contained in:
Duncan Ogilvie 2024-08-05 13:42:09 +02:00 committed by GitHub
commit d8cf398b41
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
17 changed files with 262 additions and 233 deletions

View File

@ -1,6 +1,5 @@
#include "TraceBrowser.h"
#include "TraceWidget.h"
#include "TraceFileReader.h"
#include "TraceFileSearch.h"
#include "RichTextPainter.h"
#include "main.h"
@ -52,7 +51,7 @@ TraceBrowser::TraceBrowser(TraceFileReader* traceFile, TraceWidget* parent) : Ab
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(this, SIGNAL(selectionChanged(TRACEINDEX)), this, SLOT(selectionChangedSlot(TRACEINDEX)));
connect(Bridge::getBridge(), SIGNAL(close()), this, SLOT(closeFileSlot()));
connect(getTraceFile(), SIGNAL(parseFinished()), this, SLOT(parseFinishedSlot()));
}
@ -753,7 +752,7 @@ NotDebuggingLabel:
}
}
ZydisTokenizer::InstructionToken TraceBrowser::memoryTokens(unsigned long long atIndex)
ZydisTokenizer::InstructionToken TraceBrowser::memoryTokens(TRACEINDEX atIndex)
{
duint MemoryAddress[MAX_MEMORY_OPERANDS];
duint MemoryOldContent[MAX_MEMORY_OPERANDS];
@ -773,13 +772,12 @@ ZydisTokenizer::InstructionToken TraceBrowser::memoryTokens(unsigned long long a
ZydisTokenizer::TokenizeTraceMemory(MemoryAddress[i], MemoryOldContent[i], MemoryNewContent[i], tokens);
}
fakeInstruction.tokens.insert(fakeInstruction.tokens.begin(), tokens.begin(), tokens.end());
}
return fakeInstruction;
return fakeInstruction;
}
ZydisTokenizer::InstructionToken TraceBrowser::registersTokens(unsigned long long atIndex)
ZydisTokenizer::InstructionToken TraceBrowser::registersTokens(TRACEINDEX atIndex)
{
ZydisTokenizer::InstructionToken fakeInstruction = ZydisTokenizer::InstructionToken();
REGDUMP now = getTraceFile()->Registers(atIndex);
@ -859,6 +857,12 @@ void TraceBrowser::setupRightClickContextMenu()
mMenuBuilder->addMenu(makeMenu(DIcon("copy"), tr("&Copy")), copyMenu);
mMenuBuilder->addMenu(makeMenu(DIcon("dump"), tr("&Follow in Dump")), [this](QMenu * menu)
{
mParent->setupFollowMenu(menu);
return true;
});
mCommonActions->build(mMenuBuilder, CommonActions::ActionDisasm | CommonActions::ActionBreakpoint | CommonActions::ActionLabel | CommonActions::ActionComment | CommonActions::ActionBookmark);
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);
@ -900,7 +904,7 @@ void TraceBrowser::setupRightClickContextMenu()
duint MemoryNewContent[MAX_MEMORY_OPERANDS];
bool MemoryIsValid[MAX_MEMORY_OPERANDS];
int MemoryOperandsCount;
unsigned long long index;
TRACEINDEX index;
if(!isFileOpened())
return false;
@ -1164,7 +1168,7 @@ void TraceBrowser::keyPressEvent(QKeyEvent* event)
AbstractTableView::keyPressEvent(event);
}
void TraceBrowser::selectionChangedSlot(unsigned long long selection)
void TraceBrowser::selectionChangedSlot(TRACEINDEX selection)
{
if(mTraceSyncCpu && isFileOpened())
{
@ -1360,7 +1364,7 @@ void TraceBrowser::mnemonicHelpSlot()
emit displayLogWidget();
}
void TraceBrowser::disasm(unsigned long long index, bool history)
void TraceBrowser::disasm(TRACEINDEX index, bool history)
{
setSingleSelection(index);
makeVisible(index);
@ -1375,7 +1379,7 @@ void TraceBrowser::disasmByAddress(duint address, bool history)
if(!mParent->loadDumpFully())
return;
auto references = getTraceFile()->getDump()->getReferences(address, address);
unsigned long long index;
TRACEINDEX index;
bool found = false;
if(references.empty())
{
@ -1513,7 +1517,7 @@ void TraceBrowser::pushSelectionInto(bool copyBytes, QTextStream & stream, QText
const int memoryLen = getColumnWidth(Memory) / getCharWidth() - 1;
if(htmlStream)
*htmlStream << QString("<table style=\"border-width:0px;border-color:#000000;font-family:%1;font-size:%2px;\">").arg(font().family()).arg(getRowHeight());
for(unsigned long long i = getSelectionStart(); i <= getSelectionEnd(); i++)
for(TRACEINDEX i = getSelectionStart(); i <= getSelectionEnd(); i++)
{
if(i != getSelectionStart())
stream << "\r\n";
@ -1741,7 +1745,7 @@ void TraceBrowser::copyRvaSlot()
if(getTraceFile() == nullptr)
return;
for(unsigned long long i = getSelectionStart(); i <= getSelectionEnd(); i++)
for(TRACEINDEX i = getSelectionStart(); i <= getSelectionEnd(); i++)
{
duint cip = getTraceFile()->Registers(i).regcontext.cip;
duint base = DbgFunctions()->ModBaseFromAddr(cip);
@ -1766,7 +1770,7 @@ void TraceBrowser::copyFileOffsetSlot()
if(getTraceFile() == nullptr)
return;
for(unsigned long long i = getSelectionStart(); i <= getSelectionEnd(); i++)
for(TRACEINDEX i = getSelectionStart(); i <= getSelectionEnd(); i++)
{
duint cip = getTraceFile()->Registers(i).regcontext.cip;
cip = DbgFunctions()->VaToFileOffset(cip);

View File

@ -3,8 +3,8 @@
#include "AbstractTableView.h"
#include "VaHistory.h"
#include "QZydis.h"
#include "TraceFileReader.h"
class TraceFileReader;
class TraceWidget;
class BreakpointMenu;
class CommonActions;
@ -59,8 +59,8 @@ private:
void mouseDoubleClickEvent(QMouseEvent* event) override;
void keyPressEvent(QKeyEvent* event) override;
ZydisTokenizer::InstructionToken memoryTokens(unsigned long long atIndex);
ZydisTokenizer::InstructionToken registersTokens(unsigned long long atIndex);
ZydisTokenizer::InstructionToken memoryTokens(TRACEINDEX atIndex);
ZydisTokenizer::InstructionToken registersTokens(TRACEINDEX atIndex);
VaHistory mHistory;
MenuBuilder* mMenuBuilder;
CommonActions* mCommonActions;
@ -146,7 +146,7 @@ private:
signals:
void displayLogWidget();
void selectionChanged(unsigned long long selection);
void selectionChanged(TRACEINDEX selection);
void xrefSignal(duint addr);
void closeFile();
@ -159,7 +159,7 @@ public slots:
void closeDeleteSlot();
void parseFinishedSlot();
void tokenizerConfigUpdatedSlot();
void selectionChangedSlot(unsigned long long selection);
void selectionChangedSlot(TRACEINDEX selection);
void gotoSlot();
void gotoIndexSlot();
@ -192,7 +192,7 @@ public slots:
private:
// Go to by index
void disasm(unsigned long long index, bool history = true);
void disasm(TRACEINDEX index, bool history = true);
// Go to by address, display the Xref dialog if multiple indicies are found
void disasmByAddress(duint address, bool history = true);
TraceWidget* mParent;

View File

@ -1,11 +1,9 @@
#include "TraceDump.h"
#include "TraceWidget.h"
#include "TraceFileReader.h"
#include "TraceFileDump.h"
#include <QMessageBox>
#include <QClipboard>
#include <QFileDialog>
#include <QToolTip>
#include "TraceDump.h"
#include "TraceWidget.h"
#include "Configuration.h"
#include "Bridge.h"
#include "HexEditDialog.h"

View File

@ -7,7 +7,7 @@
TraceFileDump::TraceFileDump()
{
maxIndex = 0ull;
maxIndex = static_cast<TRACEINDEX>(0);
enabled = false;
}
@ -27,7 +27,7 @@ TraceFileDump::~TraceFileDump()
void TraceFileDump::clear()
{
maxIndex = 0ull;
maxIndex = static_cast<TRACEINDEX>(0);
dump.clear();
}
@ -48,7 +48,7 @@ bool TraceFileDump::isValidReadPtr(duint address) const
return false;
}
void TraceFileDump::getBytes(duint addr, duint size, unsigned long long index, void* buffer) const
void TraceFileDump::getBytes(duint addr, duint size, TRACEINDEX index, void* buffer) const
{
if(!isEnabled())
return;
@ -135,12 +135,12 @@ void TraceFileDump::getBytes(duint addr, duint size, unsigned long long index, v
}
// find references to the memory address
std::vector<unsigned long long> TraceFileDump::getReferences(duint startAddr, duint endAddr) const
std::vector<TRACEINDEX> TraceFileDump::getReferences(duint startAddr, duint endAddr) const
{
if(!isEnabled())
return {};
std::vector<unsigned long long> index;
std::vector<TRACEINDEX> index;
if(endAddr < startAddr)
std::swap(endAddr, startAddr);
// find references to the memory address
@ -154,7 +154,7 @@ std::vector<unsigned long long> TraceFileDump::getReferences(duint startAddr, du
return index;
// rearrange the array and remove duplicates
std::sort(index.begin(), index.end());
std::vector<unsigned long long> result;
std::vector<TRACEINDEX> result;
result.push_back(index[0]);
for(size_t i = 1; i < index.size(); i++)
{
@ -236,12 +236,12 @@ TraceFileDumpMemoryPage::TraceFileDumpMemoryPage(TraceFileDump* dump, QObject* p
this->dump = dump;
}
void TraceFileDumpMemoryPage::setSelectedIndex(unsigned long long index)
void TraceFileDumpMemoryPage::setSelectedIndex(TRACEINDEX index)
{
if(dump)
selectedIndex = std::min(index, dump->getMaxIndex());
else
selectedIndex = 0ull;
selectedIndex = static_cast<TRACEINDEX>(0);
}
bool TraceFileDumpMemoryPage::isAvailable() const
@ -249,7 +249,7 @@ bool TraceFileDumpMemoryPage::isAvailable() const
return !!this->dump;
}
unsigned long long TraceFileDumpMemoryPage::getSelectedIndex() const
TRACEINDEX TraceFileDumpMemoryPage::getSelectedIndex() const
{
return selectedIndex;
}

View File

@ -5,13 +5,15 @@
#include <QMutex>
#include "MemoryPage.h"
typedef DWORD TRACEINDEX;
class TraceFileDump
{
public:
struct Key
{
duint addr;
unsigned long long index;
TRACEINDEX 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.
@ -39,8 +41,8 @@ public:
}
// Read a byte at "addr" at the moment given in "index"
bool isValidReadPtr(duint addr) const;
void getBytes(duint addr, duint size, unsigned long long index, void* buffer) const;
std::vector<unsigned long long> getReferences(duint startAddr, duint endAddr) const;
void getBytes(duint addr, duint size, TRACEINDEX index, void* buffer) const;
std::vector<TRACEINDEX> 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);
@ -48,7 +50,7 @@ public:
{
maxIndex++;
}
inline unsigned long long getMaxIndex()
inline TRACEINDEX getMaxIndex()
{
return maxIndex;
}
@ -58,7 +60,7 @@ public:
private:
std::map<Key, DumpRecord> dump;
// maxIndex is the last index included here. As the debuggee steps there will be new data coming.
unsigned long long maxIndex;
TRACEINDEX maxIndex;
bool enabled;
};
@ -69,10 +71,10 @@ public:
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 setSelectedIndex(TRACEINDEX index);
TRACEINDEX getSelectedIndex() const;
bool isAvailable() const;
private:
TraceFileDump* dump;
unsigned long long selectedIndex = 0ull;
TRACEINDEX selectedIndex = static_cast<TRACEINDEX>(0);
};

View File

@ -121,7 +121,7 @@ bool TraceFileReader::isError(QString & reason) const
//}
// Return the count of instructions
unsigned long long TraceFileReader::Length() const
TRACEINDEX TraceFileReader::Length() const
{
return length;
}
@ -136,7 +136,7 @@ TraceFileDump* TraceFileReader::getDump()
return &dump;
}
QString TraceFileReader::getIndexText(unsigned long long index) const
QString TraceFileReader::getIndexText(TRACEINDEX index) const
{
QString indexString;
indexString = QString::number(index, 16).toUpper();
@ -171,9 +171,9 @@ QString TraceFileReader::FileName() const
}
// Return the registers context at a given index
REGDUMP TraceFileReader::Registers(unsigned long long index)
REGDUMP TraceFileReader::Registers(TRACEINDEX index)
{
unsigned long long base;
TRACEINDEX base;
TraceFilePage* page = getPage(index, &base);
if(page == nullptr)
{
@ -186,9 +186,9 @@ REGDUMP TraceFileReader::Registers(unsigned long long index)
}
// Return the opcode at a given index. buffer must be 16 bytes long.
void TraceFileReader::OpCode(unsigned long long index, unsigned char* buffer, int* opcodeSize)
void TraceFileReader::OpCode(TRACEINDEX index, unsigned char* buffer, int* opcodeSize)
{
unsigned long long base;
TRACEINDEX base;
TraceFilePage* page = getPage(index, &base);
if(page == nullptr)
{
@ -201,18 +201,18 @@ void TraceFileReader::OpCode(unsigned long long index, unsigned char* buffer, in
}
// Return the disassembled instruction at a given index.
const Instruction_t & TraceFileReader::Instruction(unsigned long long index)
const Instruction_t & TraceFileReader::Instruction(TRACEINDEX index)
{
unsigned long long base;
TRACEINDEX base;
TraceFilePage* page = getPage(index, &base);
// The caller must guarantee page is not null, most likely they have already called some other getters.
return page->Instruction(index - base, *mDisasm);
}
// Return the thread id at a given index
DWORD TraceFileReader::ThreadId(unsigned long long index)
DWORD TraceFileReader::ThreadId(TRACEINDEX index)
{
unsigned long long base;
TRACEINDEX base;
TraceFilePage* page = getPage(index, &base);
if(page == nullptr)
return 0;
@ -221,9 +221,9 @@ DWORD TraceFileReader::ThreadId(unsigned long long index)
}
// Return the number of recorded memory accesses at a given index
int TraceFileReader::MemoryAccessCount(unsigned long long index)
int TraceFileReader::MemoryAccessCount(TRACEINDEX index)
{
unsigned long long base;
TRACEINDEX base;
TraceFilePage* page = getPage(index, &base);
if(page == nullptr)
return 0;
@ -232,9 +232,9 @@ int TraceFileReader::MemoryAccessCount(unsigned long long index)
}
// Return the memory access info at a given index
void TraceFileReader::MemoryAccessInfo(unsigned long long index, duint* address, duint* oldMemory, duint* newMemory, bool* isValid)
void TraceFileReader::MemoryAccessInfo(TRACEINDEX index, duint* address, duint* oldMemory, duint* newMemory, bool* isValid)
{
unsigned long long base;
TRACEINDEX base;
TraceFilePage* page = getPage(index, &base);
if(page == nullptr)
return;
@ -266,7 +266,7 @@ static size_t getMaxCachedPages()
}
// Used internally to get the page for the given index and read from disk if necessary
TraceFilePage* TraceFileReader::getPage(unsigned long long index, unsigned long long* base)
TraceFilePage* TraceFileReader::getPage(TRACEINDEX index, TRACEINDEX* base)
{
// Try to access the most recently used page
if(lastAccessedPage)
@ -484,8 +484,8 @@ static bool readBlock(QFile & traceFile)
void TraceFileParser::run()
{
TraceFileReader* that = dynamic_cast<TraceFileReader*>(parent());
unsigned long long index = 0;
unsigned long long lastIndex = 0;
TRACEINDEX index = 0;
TRACEINDEX lastIndex = 0;
if(that == NULL)
{
return; //Error
@ -543,8 +543,8 @@ void TraceFileParser::run()
// Remove last page from memory and read from disk again to show updates
void TraceFileReader::purgeLastPage()
{
unsigned long long index = 0;
unsigned long long lastIndex = 0;
TRACEINDEX index = 0;
TRACEINDEX lastIndex = 0;
bool isBlockExist = false;
const bool previousEmpty = Length() == 0;
if(length > 0)
@ -601,7 +601,7 @@ void TraceFileReader::purgeLastPage()
}
// Extract memory access information of given index into dump object
void TraceFileReader::buildDump(unsigned long long index)
void TraceFileReader::buildDump(TRACEINDEX index)
{
unsigned char opcode[MAX_DISASM_BUFFER];
int opcodeSize;
@ -707,7 +707,7 @@ void TraceFileReader::buildDump(unsigned long long index)
}
// Build dump index to the given index
void TraceFileReader::buildDumpTo(unsigned long long index)
void TraceFileReader::buildDumpTo(TRACEINDEX index)
{
auto start = dump.getMaxIndex(); // Don't re-add existing dump
for(auto i = start + 1; i <= index; i++)
@ -717,13 +717,13 @@ void TraceFileReader::buildDumpTo(unsigned long long index)
}
}
std::vector<unsigned long long> TraceFileReader::getReferences(duint startAddr, duint endAddr) const
std::vector<TRACEINDEX> 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)
TraceFilePage::TraceFilePage(TraceFileReader* parent, unsigned long long fileOffset, TRACEINDEX maxLength)
{
DWORD lastThreadId = 0;
union
@ -837,28 +837,28 @@ TraceFilePage::TraceFilePage(TraceFileReader* parent, unsigned long long fileOff
}
}
unsigned long long TraceFilePage::Length() const
TRACEINDEX TraceFilePage::Length() const
{
return length;
}
const REGDUMP & TraceFilePage::Registers(unsigned long long index) const
const REGDUMP & TraceFilePage::Registers(TRACEINDEX index) const
{
return mRegisters.at(index);
}
void TraceFilePage::OpCode(unsigned long long index, unsigned char* buffer, int* opcodeSize) const
void TraceFilePage::OpCode(TRACEINDEX index, unsigned char* buffer, int* opcodeSize) const
{
*opcodeSize = this->opcodeSize.at(index);
memcpy(buffer, opcodes.constData() + opcodeOffset.at(index), *opcodeSize);
}
const Instruction_t & TraceFilePage::Instruction(unsigned long long index, QZydis & mDisasm)
const Instruction_t & TraceFilePage::Instruction(TRACEINDEX index, QZydis & mDisasm)
{
if(instructions.size() == 0)
{
instructions.reserve(length);
for(unsigned long long i = 0; i < length; i++)
for(TRACEINDEX i = 0; i < length; i++)
{
instructions.emplace_back(mDisasm.DisassembleAt((const byte_t*)opcodes.constData() + opcodeOffset.at(i), opcodeSize.at(i), 0, Registers(i).regcontext.cip, false));
}
@ -866,12 +866,12 @@ const Instruction_t & TraceFilePage::Instruction(unsigned long long index, QZydi
return instructions.at(index);
}
DWORD TraceFilePage::ThreadId(unsigned long long index) const
DWORD TraceFilePage::ThreadId(TRACEINDEX index) const
{
return threadId.at(index);
}
int TraceFilePage::MemoryAccessCount(unsigned long long index) const
int TraceFilePage::MemoryAccessCount(TRACEINDEX index) const
{
size_t a = memoryOperandOffset.at(index);
if(index == length - 1)
@ -880,7 +880,7 @@ int TraceFilePage::MemoryAccessCount(unsigned long long index) const
return (int)(memoryOperandOffset.at(index + 1) - a);
}
void TraceFilePage::MemoryAccessInfo(unsigned long long index, duint* address, duint* oldMemory, duint* newMemory, bool* isValid) const
void TraceFilePage::MemoryAccessInfo(TRACEINDEX index, duint* address, duint* oldMemory, duint* newMemory, bool* isValid) const
{
auto count = MemoryAccessCount(index);
auto base = memoryOperandOffset.at(index);

View File

@ -25,20 +25,20 @@ public:
bool isError(QString & reason) 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;
QString getIndexText(TRACEINDEX index) const;
unsigned long long Length() const;
TRACEINDEX Length() const;
uint64_t FileSize() const;
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);
REGDUMP Registers(TRACEINDEX index);
void OpCode(TRACEINDEX index, unsigned char* buffer, int* opcodeSize);
const Instruction_t & Instruction(TRACEINDEX index);
// Get thread ID
DWORD ThreadId(unsigned long long index);
DWORD ThreadId(TRACEINDEX index);
// Get number of memory accesses
int MemoryAccessCount(unsigned long long index);
int MemoryAccessCount(TRACEINDEX 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);
void MemoryAccessInfo(TRACEINDEX index, duint* address, duint* oldMemory, duint* newMemory, bool* isValid);
// Get hash of EXE
duint HashValue() const;
const QString & ExePath() const;
@ -46,8 +46,8 @@ public:
void purgeLastPage();
void buildDumpTo(unsigned long long index);
std::vector<unsigned long long> getReferences(duint startAddr, duint endAddr) const;
void buildDumpTo(TRACEINDEX index);
std::vector<TRACEINDEX> getReferences(duint startAddr, duint endAddr) const;
TraceFileDump* getDump();
signals:
@ -60,7 +60,7 @@ private slots:
void tokenizerUpdatedSlot();
private:
typedef std::pair<unsigned long long, unsigned long long> Range;
typedef std::pair<TRACEINDEX, TRACEINDEX> Range;
struct RangeCompare //from addrinfo.h
{
bool operator()(const Range & a, const Range & b) const //a before b?
@ -71,7 +71,7 @@ private:
QFile traceFile;
qint64 fileSize = 0;
unsigned long long length = 0;
TRACEINDEX length = 0;
duint hashValue = 0;
QString EXEPath;
std::vector<std::pair<unsigned long long, Range>> fileIndex; //index;<file offset;length>
@ -79,15 +79,15 @@ private:
bool error = true;
QString errorMessage;
TraceFilePage* lastAccessedPage = nullptr;
unsigned long long lastAccessedIndexOffset = 0;
TRACEINDEX lastAccessedIndexOffset = 0;
friend class TraceFileParser;
friend class TraceFilePage;
TraceFileParser* parser = nullptr;
std::map<Range, TraceFilePage, RangeCompare> pages;
TraceFilePage* getPage(unsigned long long index, unsigned long long* base);
TraceFilePage* getPage(TRACEINDEX index, TRACEINDEX* base);
TraceFileDump dump;
void buildDump(unsigned long long index);
void buildDump(TRACEINDEX index);
QZydis* mDisasm;
};

View File

@ -16,14 +16,14 @@ class TraceFileParser : public QThread
class TraceFilePage
{
public:
TraceFilePage(TraceFileReader* parent, unsigned long long fileOffset, unsigned long long maxLength);
unsigned long long Length() const;
const REGDUMP & Registers(unsigned long long index) const;
void OpCode(unsigned long long index, unsigned char* buffer, int* opcodeSize) const;
const Instruction_t & Instruction(unsigned long long index, QZydis & mDisasm);
DWORD ThreadId(unsigned long long index) const;
int MemoryAccessCount(unsigned long long index) const;
void MemoryAccessInfo(unsigned long long index, duint* address, duint* oldMemory, duint* newMemory, bool* isValid) const;
TraceFilePage(TraceFileReader* parent, unsigned long long fileOffset, TRACEINDEX maxLength);
TRACEINDEX Length() const;
const REGDUMP & Registers(TRACEINDEX index) const;
void OpCode(TRACEINDEX index, unsigned char* buffer, int* opcodeSize) const;
const Instruction_t & Instruction(TRACEINDEX index, QZydis & mDisasm);
DWORD ThreadId(TRACEINDEX index) const;
int MemoryAccessCount(TRACEINDEX index) const;
void MemoryAccessInfo(TRACEINDEX index, duint* address, duint* oldMemory, duint* newMemory, bool* isValid) const;
FILETIME lastAccessed; //system user time
@ -43,5 +43,5 @@ private:
std::vector<duint> oldMemory;
std::vector<duint> newMemory;
std::vector<DWORD> threadId;
unsigned long long length;
TRACEINDEX length;
};

View File

@ -2,7 +2,6 @@
#include "TraceWidget.h"
#include "TraceDump.h"
#include "TraceBrowser.h"
#include "TraceFileReader.h"
#include "CPUInfoBox.h"
#include "zydis_wrapper.h"
@ -36,7 +35,7 @@ TraceInfoBox::~TraceInfoBox()
}
void TraceInfoBox::update(unsigned long long selection, TraceFileReader* traceFile, const REGDUMP & registers)
void TraceInfoBox::update(TRACEINDEX selection, TraceFileReader* traceFile, const REGDUMP & registers)
{
duint infoline = 0;
Zydis zydis;
@ -234,111 +233,12 @@ 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)
{
TraceFileReader* traceFile = mParent->getTraceFile();
const TraceFileDump* traceDump = traceFile->getDump();
if(!traceDump->isEnabled())
return;
//most basic follow action
addFollowMenuItem(menu, tr("&Selected Address"), va);
//add follow actions
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, [&registers](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"));
setupFollowMenu(&followMenu, mCurAddr);
mParent->setupFollowMenu(&followMenu);
menu.addMenu(&followMenu);
QMenu copyMenu(tr("&Copy"), this);
setupCopyMenu(&copyMenu);
@ -346,21 +246,6 @@ void TraceInfoBox::contextMenuSlot(QPoint pos)
menu.exec(mapToGlobal(pos)); //execute context menu
}
/**
* @brief TraceInfoBox::followActionSlot Called when follow action is clicked
*/
void TraceInfoBox::followActionSlot()
{
QAction* action = qobject_cast<QAction*>(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"));

View File

@ -1,9 +1,9 @@
#pragma once
#include "StdTable.h"
#include "TraceFileReader.h"
class TraceWidget;
class TraceFileReader;
class TraceInfoBox : public StdTable
{
@ -11,16 +11,13 @@ 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);
void update(TRACEINDEX selection, TraceFileReader* traceFile, const REGDUMP & registers);
void clear();
public slots:
void contextMenuSlot(QPoint pos);
void followActionSlot();
private:
void setupContextMenu();

View File

@ -1,18 +1,24 @@
#include <QMouseEvent>
#include "TraceRegisters.h"
#include "TraceWidget.h"
#include "TraceDump.h"
#include "Configuration.h"
#include "EditFloatRegister.h"
#include "StringUtil.h"
#include "MiscUtil.h"
TraceRegisters::TraceRegisters(QWidget* parent) : RegistersView(parent)
TraceRegisters::TraceRegisters(TraceWidget* parent) : RegistersView(parent)
{
mParent = parent;
wCM_CopySIMDRegister = setupAction(DIcon("copy"), tr("Copy floating point value"));
connect(wCM_CopySIMDRegister, SIGNAL(triggered()), this, SLOT(onCopySIMDRegister()));
connect(this, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(displayCustomContextMenuSlot(QPoint)));
wCM_SetCurrentRegister = setupAction(tr("Set as current value"));
connect(wCM_SetCurrentRegister, SIGNAL(triggered()), this, SLOT(onSetCurrentRegister()));
wCM_FollowInDump = new QAction(DIcon("dump"), tr("Follow in Dump"), this);
connect(wCM_FollowInDump, SIGNAL(triggered()), this, SLOT(onFollowInDump()));
}
void TraceRegisters::setRegisters(REGDUMP* registers)
@ -35,6 +41,10 @@ void TraceRegisters::displayCustomContextMenuSlot(QPoint pos)
if(mSelected != UNKNOWN)
{
if(mCANSTOREADDRESS.contains(mSelected))
{
menu.addAction(wCM_FollowInDump);
}
menu.addAction(wCM_CopyToClipboard);
if(mFPUx87_80BITSDISPLAY.contains(mSelected))
{
@ -163,3 +173,13 @@ void TraceRegisters::mouseDoubleClickEvent(QMouseEvent* event)
onCopySIMDRegister();
// double clicked on GPR: nothing to do (copy?)
}
void TraceRegisters::onFollowInDump()
{
// First check if the dump is loaded
if(!mParent->getTraceFile()->getDump()->isEnabled())
if(!mParent->loadDump()) // Try to load the dump
return;
duint value = *((const duint*)registerValue(&mRegDumpStruct, mSelected));
mParent->getTraceDump()->printDumpAt(value, true, true, true);
}

View File

@ -2,11 +2,13 @@
#include "RegistersView.h"
class TraceWidget;
class TraceRegisters : public RegistersView
{
Q_OBJECT
public:
TraceRegisters(QWidget* parent = nullptr);
TraceRegisters(TraceWidget* parent = nullptr);
void setRegisters(REGDUMP* registers);
void setActive(bool isActive);
@ -15,11 +17,14 @@ public slots:
virtual void displayCustomContextMenuSlot(QPoint pos);
void onCopySIMDRegister();
void onSetCurrentRegister();
void onFollowInDump();
protected:
virtual void mouseDoubleClickEvent(QMouseEvent* event);
private:
TraceWidget* mParent;
QAction* wCM_CopySIMDRegister;
QAction* wCM_SetCurrentRegister;
QAction* wCM_FollowInDump;
};

View File

@ -1,8 +1,6 @@
#include "TraceWidget.h"
#include "TraceStack.h"
#include "TraceDump.h"
#include "TraceFileReader.h"
#include "TraceFileDump.h"
#include "TraceBrowser.h"
#include "CPUDump.h"
#include <QClipboard>

View File

@ -60,7 +60,7 @@ 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(mTraceBrowser, SIGNAL(selectionChanged(unsigned long long)), this, SLOT(traceSelectionChanged(unsigned long long)));
connect(mTraceBrowser, SIGNAL(selectionChanged(TRACEINDEX)), this, SLOT(traceSelectionChanged(TRACEINDEX)));
connect(mTraceBrowser, SIGNAL(displayLogWidget()), this, SLOT(displayLogWidgetSlot()));
connect(mTraceFile, SIGNAL(parseFinished()), this, SLOT(parseFinishedSlot()));
connect(mTraceBrowser, SIGNAL(closeFile()), this, SLOT(closeFileSlot()));
@ -116,7 +116,7 @@ TraceWidget::~TraceWidget()
delete ui;
}
void TraceWidget::traceSelectionChanged(unsigned long long selection)
void TraceWidget::traceSelectionChanged(TRACEINDEX selection)
{
REGDUMP registers;
if(mTraceFile != nullptr)
@ -253,7 +253,7 @@ bool TraceWidget::loadDumpFully()
return true;
}
void TraceWidget::setupDumpInitialAddresses(unsigned long long selection)
void TraceWidget::setupDumpInitialAddresses(TRACEINDEX selection)
{
// Setting the initial address of dump view
duint initialAddress;
@ -277,3 +277,123 @@ void TraceWidget::setupDumpInitialAddresses(unsigned long long selection)
// Setting the initial address of stack view
mStack->printDumpAt(mTraceFile->Registers(selection).regcontext.csp, false, true, true);
}
/**
* @brief TraceWidget::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 TraceWidget::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 TraceWidget::setupFollowMenu Set up a follow menu.
* @param menu The menu to create
* @param va The selected VA
*/
void TraceWidget::setupFollowMenu(QMenu* menu)
{
const TraceFileDump* traceDump = mTraceFile->getDump();
if(!traceDump->isEnabled())
{
QAction* newAction = new QAction(tr("Load dump"), menu);
connect(newAction, SIGNAL(triggered()), this, SLOT(loadDump()));
menu->addAction(newAction);
return;
}
//add follow actions
TRACEINDEX selection = getTraceBrowser()->getInitialSelection();
REGDUMP registers = mTraceFile->Registers(selection);
duint va = registers.regcontext.cip;
Zydis zydis;
unsigned char opcode[16];
int opsize;
mTraceFile->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 = mTraceFile->MemoryAccessCount(selection);
if(MemoryOperandsCount > 0)
mTraceFile->MemoryAccessInfo(selection, MemoryAddress, MemoryOldContent, MemoryNewContent, MemoryIsValid);
//most basic follow action
addFollowMenuItem(menu, tr("&Selected Address"), va);
if(zydis.Disassemble(va, opcode, opsize))
{
for(uint8_t opindex = 0; opindex < zydis.OpCount(); opindex++)
{
size_t value = zydis.ResolveOpValue(opindex, [&registers](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);
}
}
}
}
}
/**
* @brief TraceWidget::followActionSlot Called when follow action is clicked
*/
void TraceWidget::followActionSlot()
{
QAction* action = qobject_cast<QAction*>(sender());
duint data;
#ifdef _WIN64
data = action->objectName().toULongLong(nullptr, 16);
#else
data = action->objectName().toULong(nullptr, 16);
#endif //_WIN64
mDump->printDumpAt(data, true, true, true);
}

View File

@ -2,18 +2,17 @@
#include <QWidget>
#include "Bridge.h"
#include "TraceFileReader.h"
class QVBoxLayout;
class QPushButton;
class CPUWidget;
class TraceRegisters;
class TraceBrowser;
class TraceFileReader;
class TraceFileDumpMemoryPage;
class TraceInfoBox;
class TraceDump;
class TraceStack;
class TraceFileReader;
class TraceXrefBrowseDialog;
namespace Ui
@ -47,6 +46,7 @@ public:
};
// Enable trace dump and load it fully before searching. Return false if the user cancels.
bool loadDumpFully();
void setupFollowMenu(QMenu* menu);
public slots:
// Enable trace dump in order to use these features. Return false if the user cancels.
bool loadDump();
@ -57,10 +57,11 @@ signals:
protected slots:
void displayLogWidgetSlot();
void traceSelectionChanged(unsigned long long selection);
void traceSelectionChanged(TRACEINDEX selection);
void parseFinishedSlot();
void closeFileSlot();
void xrefSlot(duint addr);
void followActionSlot();
protected:
TraceFileReader* mTraceFile;
@ -77,5 +78,6 @@ protected:
private:
Ui::TraceWidget* ui;
void setupDumpInitialAddresses(unsigned long long selection);
void setupDumpInitialAddresses(TRACEINDEX selection);
void addFollowMenuItem(QMenu* menu, QString name, duint value);
};

View File

@ -55,7 +55,7 @@ void TraceXrefBrowseDialog::setup(duint index, duint address, TraceFileReader* t
}
setWindowTitle(QString(tr("xrefs at <%1>")).arg(GetFunctionSymbol(address)));
for(duint i = 0; i < mXrefInfo.size(); i++)
for(size_t i = 0; i < mXrefInfo.size(); i++)
{
Zydis zydis;
QString disasm;

View File

@ -4,15 +4,13 @@
#include "ActionHelpers.h"
#include <QDialog>
#include <QListWidgetItem>
#include "TraceFileReader.h"
namespace Ui
{
class XrefBrowseDialog;
}
class TraceFileReader;
class TraceFileDump;
class TraceXrefBrowseDialog : public QDialog, public ActionHelper<TraceXrefBrowseDialog>
{
Q_OBJECT
@ -43,7 +41,7 @@ private:
typedef struct
{
unsigned long long index;
TRACEINDEX index;
duint addr;
} TRACE_XREF_RECORD;
std::vector<TRACE_XREF_RECORD> mXrefInfo;