Cache disassembly in trace file reader
This commit is contained in:
parent
220e1d0902
commit
35c6516df9
|
|
@ -28,11 +28,11 @@ QBeaEngine::~QBeaEngine()
|
|||
*
|
||||
* @return Return the RVA (Relative to the data pointer) of the nth instruction before the instruction pointed by ip
|
||||
*/
|
||||
ulong QBeaEngine::DisassembleBack(byte_t* data, duint base, duint size, duint ip, int n)
|
||||
ulong QBeaEngine::DisassembleBack(const byte_t* data, duint base, duint size, duint ip, int n)
|
||||
{
|
||||
int i;
|
||||
uint abuf[128], addr, back, cmdsize;
|
||||
unsigned char* pdata;
|
||||
const unsigned char* pdata;
|
||||
|
||||
// Reset Disasm Structure
|
||||
Zydis cp;
|
||||
|
|
@ -124,11 +124,11 @@ ulong QBeaEngine::DisassembleBack(byte_t* data, duint base, duint size, duint ip
|
|||
*
|
||||
* @return Return the RVA (Relative to the data pointer) of the nth instruction after the instruction pointed by ip
|
||||
*/
|
||||
ulong QBeaEngine::DisassembleNext(byte_t* data, duint base, duint size, duint ip, int n)
|
||||
ulong QBeaEngine::DisassembleNext(const byte_t* data, duint base, duint size, duint ip, int n)
|
||||
{
|
||||
int i;
|
||||
uint cmdsize;
|
||||
unsigned char* pdata;
|
||||
const unsigned char* pdata;
|
||||
|
||||
// Reset Disasm Structure
|
||||
Zydis cp;
|
||||
|
|
@ -181,7 +181,7 @@ ulong QBeaEngine::DisassembleNext(byte_t* data, duint base, duint size, duint ip
|
|||
*
|
||||
* @return Return the disassembled instruction
|
||||
*/
|
||||
Instruction_t QBeaEngine::DisassembleAt(byte_t* data, duint size, duint origBase, duint origInstRVA, bool datainstr)
|
||||
Instruction_t QBeaEngine::DisassembleAt(const byte_t* data, duint size, duint origBase, duint origInstRVA, bool datainstr)
|
||||
{
|
||||
if(datainstr)
|
||||
{
|
||||
|
|
@ -311,7 +311,7 @@ Instruction_t QBeaEngine::DisassembleAt(byte_t* data, duint size, duint origBase
|
|||
return wInst;
|
||||
}
|
||||
|
||||
Instruction_t QBeaEngine::DecodeDataAt(byte_t* data, duint size, duint origBase, duint origInstRVA, ENCODETYPE type)
|
||||
Instruction_t QBeaEngine::DecodeDataAt(const byte_t* data, duint size, duint origBase, duint origInstRVA, ENCODETYPE type)
|
||||
{
|
||||
//tokenize
|
||||
ZydisTokenizer::InstructionToken cap;
|
||||
|
|
|
|||
|
|
@ -43,10 +43,10 @@ class QBeaEngine
|
|||
public:
|
||||
explicit QBeaEngine(int maxModuleSize);
|
||||
~QBeaEngine();
|
||||
ulong DisassembleBack(byte_t* data, duint base, duint size, duint ip, int n);
|
||||
ulong DisassembleNext(byte_t* data, duint base, duint size, duint ip, int n);
|
||||
Instruction_t DisassembleAt(byte_t* data, duint size, duint origBase, duint origInstRVA, bool datainstr = true);
|
||||
Instruction_t DecodeDataAt(byte_t* data, duint size, duint origBase, duint origInstRVA, ENCODETYPE type);
|
||||
ulong DisassembleBack(const byte_t* data, duint base, duint size, duint ip, int n);
|
||||
ulong DisassembleNext(const byte_t* data, duint base, duint size, duint ip, int n);
|
||||
Instruction_t DisassembleAt(const byte_t* data, duint size, duint origBase, duint origInstRVA, bool datainstr = true);
|
||||
Instruction_t DecodeDataAt(const byte_t* data, duint size, duint origBase, duint origInstRVA, ENCODETYPE type);
|
||||
void setCodeFoldingManager(CodeFoldingHelper* CodeFoldingManager);
|
||||
void UpdateConfig();
|
||||
|
||||
|
|
|
|||
|
|
@ -35,8 +35,6 @@ TraceBrowser::TraceBrowser(QWidget* parent) : AbstractTableView(parent)
|
|||
|
||||
mAutoDisassemblyFollowSelection = false;
|
||||
|
||||
int maxModuleSize = (int)ConfigUint("Disassembler", "MaxModuleSize");
|
||||
mDisasm = new QBeaEngine(maxModuleSize);
|
||||
mHighlightingMode = false;
|
||||
mPermanentHighlightingMode = false;
|
||||
|
||||
|
|
@ -60,7 +58,6 @@ TraceBrowser::~TraceBrowser()
|
|||
mTraceFile->Close();
|
||||
delete mTraceFile;
|
||||
}
|
||||
delete mDisasm;
|
||||
}
|
||||
|
||||
bool TraceBrowser::isFileOpened() const
|
||||
|
|
@ -274,7 +271,9 @@ QString TraceBrowser::paintContent(QPainter* painter, dsint rowBase, int rowOffs
|
|||
|
||||
duint index = rowBase + rowOffset;
|
||||
duint cur_addr;
|
||||
cur_addr = mTraceFile->Registers(index).regcontext.cip;
|
||||
REGDUMP reg;
|
||||
reg = mTraceFile->Registers(index);
|
||||
cur_addr = reg.regcontext.cip;
|
||||
auto traceCount = DbgFunctions()->GetTraceRecordHitCount(cur_addr);
|
||||
bool wIsSelected = (index >= mSelection.fromIndex && index <= mSelection.toIndex);
|
||||
|
||||
|
|
@ -303,6 +302,9 @@ QString TraceBrowser::paintContent(QPainter* painter, dsint rowBase, int rowOffs
|
|||
|
||||
if(index >= mTraceFile->Length())
|
||||
return "";
|
||||
|
||||
const Instruction_t & inst = mTraceFile->Instruction(index);
|
||||
|
||||
switch(static_cast<TableColumnIndex>(col))
|
||||
{
|
||||
case Index:
|
||||
|
|
@ -464,16 +466,10 @@ NotDebuggingLabel:
|
|||
|
||||
case Opcode:
|
||||
{
|
||||
unsigned char opcodes[16];
|
||||
int opcodeSize = 0;
|
||||
mTraceFile->OpCode(index, opcodes, &opcodeSize);
|
||||
REGDUMP reg;
|
||||
reg = mTraceFile->Registers(index);
|
||||
Instruction_t inst = mDisasm->DisassembleAt(opcodes, opcodeSize, 0, cur_addr, false);
|
||||
//draw functions
|
||||
Function_t funcType;
|
||||
FUNCTYPE funcFirst = DbgGetFunctionTypeAt(cur_addr);
|
||||
FUNCTYPE funcLast = DbgGetFunctionTypeAt(cur_addr + opcodeSize - 1);
|
||||
FUNCTYPE funcLast = DbgGetFunctionTypeAt(cur_addr + inst.length - 1);
|
||||
HANDLE_RANGE_TYPE(FUNC, funcFirst, funcLast);
|
||||
switch(funcFirst)
|
||||
{
|
||||
|
|
@ -560,11 +556,6 @@ NotDebuggingLabel:
|
|||
case Disassembly:
|
||||
{
|
||||
RichTextPainter::List richText;
|
||||
unsigned char opcodes[16];
|
||||
int opcodeSize = 0;
|
||||
mTraceFile->OpCode(index, opcodes, &opcodeSize);
|
||||
|
||||
Instruction_t inst = mDisasm->DisassembleAt(opcodes, opcodeSize, 0, cur_addr, false);
|
||||
|
||||
int loopsize = 0;
|
||||
int depth = 0;
|
||||
|
|
@ -572,7 +563,7 @@ NotDebuggingLabel:
|
|||
while(1) //paint all loop depths
|
||||
{
|
||||
LOOPTYPE loopFirst = DbgGetLoopTypeAt(cur_addr, depth);
|
||||
LOOPTYPE loopLast = DbgGetLoopTypeAt(cur_addr + opcodeSize - 1, depth);
|
||||
LOOPTYPE loopLast = DbgGetLoopTypeAt(cur_addr + inst.length - 1, depth);
|
||||
HANDLE_RANGE_TYPE(LOOP, loopFirst, loopLast);
|
||||
if(loopFirst == LOOP_NONE)
|
||||
break;
|
||||
|
|
@ -881,14 +872,6 @@ void TraceBrowser::setupRightClickContextMenu()
|
|||
menu->addSeparator();
|
||||
}
|
||||
menu->addAction(QString("ThreadID: %1").arg(mTraceFile->ThreadId(index)));
|
||||
if(index + 1 < mTraceFile->Length())
|
||||
{
|
||||
menu->addAction(QString("LastError: %1 -> %2").arg(ToPtrString(mTraceFile->Registers(index).lastError.code)).arg(ToPtrString(mTraceFile->Registers(index + 1).lastError.code)));
|
||||
}
|
||||
else
|
||||
{
|
||||
menu->addAction(QString("LastError: %1").arg(ToPtrString(mTraceFile->Registers(index).lastError.code)));
|
||||
}
|
||||
return true;
|
||||
});
|
||||
mMenuBuilder->addMenu(makeMenu(tr("Information")), infoMenu);
|
||||
|
|
@ -933,11 +916,7 @@ void TraceBrowser::mousePressEvent(QMouseEvent* event)
|
|||
int columnPosition = 0;
|
||||
if(getColumnIndexFromX(event->x()) == Disassembly)
|
||||
{
|
||||
Instruction_t inst;
|
||||
unsigned char opcode[16];
|
||||
int opcodeSize;
|
||||
mTraceFile->OpCode(index, opcode, &opcodeSize);
|
||||
tokens = mDisasm->DisassembleAt(opcode, opcodeSize, mTraceFile->Registers(index).regcontext.cip, 0).tokens;
|
||||
tokens = mTraceFile->Instruction(index).tokens;
|
||||
columnPosition = getColumnPosition(Disassembly);
|
||||
}
|
||||
else if(getColumnIndexFromX(event->x()) == TableColumnIndex::Registers)
|
||||
|
|
@ -1128,7 +1107,6 @@ void TraceBrowser::onSelectionChanged(unsigned long long selection)
|
|||
|
||||
void TraceBrowser::tokenizerConfigUpdatedSlot()
|
||||
{
|
||||
mDisasm->UpdateConfig();
|
||||
mPermanentHighlightingMode = ConfigBool("Disassembler", "PermanentHighlightingMode");
|
||||
}
|
||||
|
||||
|
|
@ -1187,7 +1165,6 @@ void TraceBrowser::updateColors()
|
|||
{
|
||||
AbstractTableView::updateColors();
|
||||
//ZydisTokenizer::UpdateColors(); //Already called in disassembly
|
||||
mDisasm->UpdateConfig();
|
||||
mBackgroundColor = ConfigColor("DisassemblyBackgroundColor");
|
||||
|
||||
mInstructionHighlightColor = ConfigColor("InstructionHighlightColor");
|
||||
|
|
@ -1321,7 +1298,10 @@ void TraceBrowser::parseFinishedSlot()
|
|||
mMRUList->addEntry(mFileName);
|
||||
mMRUList->save();
|
||||
}
|
||||
setSingleSelection(0);
|
||||
makeVisible(0);
|
||||
emit Bridge::getBridge()->updateTraceBrowser();
|
||||
emit selectionChanged(getInitialSelection());
|
||||
}
|
||||
|
||||
void TraceBrowser::gotoSlot()
|
||||
|
|
@ -1403,12 +1383,8 @@ void TraceBrowser::pushSelectionInto(bool copyBytes, QTextStream & stream, QText
|
|||
{
|
||||
if(i != getSelectionStart())
|
||||
stream << "\r\n";
|
||||
duint cur_addr = mTraceFile->Registers(i).regcontext.cip;
|
||||
unsigned char opcode[16];
|
||||
int opcodeSize;
|
||||
mTraceFile->OpCode(i, opcode, &opcodeSize);
|
||||
Instruction_t inst;
|
||||
inst = mDisasm->DisassembleAt(opcode, opcodeSize, cur_addr, 0);
|
||||
const Instruction_t & inst = mTraceFile->Instruction(i);
|
||||
duint cur_addr = inst.rva;
|
||||
QString address = getAddrText(cur_addr, 0, addressLen > sizeof(duint) * 2 + 1);
|
||||
QString bytes;
|
||||
QString bytesHTML;
|
||||
|
|
@ -1591,10 +1567,7 @@ void TraceBrowser::copyDisassemblySlot()
|
|||
clipboardHtml += "<br/>";
|
||||
}
|
||||
RichTextPainter::List richText;
|
||||
unsigned char opcode[16];
|
||||
int opcodeSize;
|
||||
mTraceFile->OpCode(i, opcode, &opcodeSize);
|
||||
Instruction_t inst = mDisasm->DisassembleAt(opcode, opcodeSize, mTraceFile->Registers(i).regcontext.cip, 0);
|
||||
const Instruction_t & inst = mTraceFile->Instruction(i);
|
||||
ZydisTokenizer::TokenToRichText(inst.tokens, richText, 0);
|
||||
RichTextPainter::htmlRichText(richText, clipboardHtml, clipboard);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -77,7 +77,6 @@ private:
|
|||
bool mAutoDisassemblyFollowSelection;
|
||||
|
||||
TraceFileReader* mTraceFile;
|
||||
QBeaEngine* mDisasm;
|
||||
BreakpointMenu* mBreakpointMenu;
|
||||
MRUList* mMRUList;
|
||||
QString mFileName;
|
||||
|
|
|
|||
|
|
@ -15,6 +15,16 @@ TraceFileReader::TraceFileReader(QObject* parent) : QObject(parent)
|
|||
lastAccessedIndexOffset = 0;
|
||||
hashValue = 0;
|
||||
EXEPath.clear();
|
||||
|
||||
int maxModuleSize = (int)ConfigUint("Disassembler", "MaxModuleSize");
|
||||
mDisasm = new QBeaEngine(maxModuleSize);
|
||||
connect(Config(), SIGNAL(tokenizerConfigUpdated()), this, SLOT(tokenizerUpdatedSlot()));
|
||||
connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(tokenizerUpdatedSlot()));
|
||||
}
|
||||
|
||||
TraceFileReader::~TraceFileReader()
|
||||
{
|
||||
delete mDisasm;
|
||||
}
|
||||
|
||||
bool TraceFileReader::Open(const QString & fileName)
|
||||
|
|
@ -134,7 +144,7 @@ duint TraceFileReader::HashValue() const
|
|||
}
|
||||
|
||||
// Return the executable name of executable
|
||||
QString TraceFileReader::ExePath() const
|
||||
const QString & TraceFileReader::ExePath() const
|
||||
{
|
||||
return EXEPath;
|
||||
}
|
||||
|
|
@ -169,6 +179,15 @@ void TraceFileReader::OpCode(unsigned long long index, unsigned char* buffer, in
|
|||
page->OpCode(index - base, buffer, opcodeSize);
|
||||
}
|
||||
|
||||
// Return the disassembled instruction at a given index.
|
||||
const Instruction_t & TraceFileReader::Instruction(unsigned long long index)
|
||||
{
|
||||
unsigned long long 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)
|
||||
{
|
||||
|
|
@ -205,7 +224,7 @@ void TraceFileReader::MemoryAccessInfo(unsigned long long index, duint* address,
|
|||
// 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)
|
||||
{
|
||||
// Try to access the most recent used page
|
||||
// Try to access the most recently used page
|
||||
if(lastAccessedPage)
|
||||
{
|
||||
if(index >= lastAccessedIndexOffset && index < lastAccessedIndexOffset + lastAccessedPage->Length())
|
||||
|
|
@ -300,6 +319,14 @@ TraceFilePage* TraceFileReader::getPage(unsigned long long index, unsigned long
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void TraceFileReader::tokenizerUpdatedSlot()
|
||||
{
|
||||
mDisasm->UpdateConfig();
|
||||
for(auto & i : pages)
|
||||
i.second.updateInstructions();
|
||||
}
|
||||
|
||||
//Parser
|
||||
|
||||
static bool checkKey(const QJsonObject & root, const QString & key, const QString & value)
|
||||
|
|
@ -639,7 +666,7 @@ unsigned long long TraceFilePage::Length() const
|
|||
return length;
|
||||
}
|
||||
|
||||
REGDUMP TraceFilePage::Registers(unsigned long long index) const
|
||||
const REGDUMP & TraceFilePage::Registers(unsigned long long index) const
|
||||
{
|
||||
return mRegisters.at(index);
|
||||
}
|
||||
|
|
@ -650,6 +677,19 @@ void TraceFilePage::OpCode(unsigned long long index, unsigned char* buffer, int*
|
|||
memcpy(buffer, opcodes.constData() + opcodeOffset.at(index), *opcodeSize);
|
||||
}
|
||||
|
||||
const Instruction_t & TraceFilePage::Instruction(unsigned long long index, QBeaEngine & mDisasm)
|
||||
{
|
||||
if(instructions.size() == 0)
|
||||
{
|
||||
instructions.reserve(length);
|
||||
for(unsigned long long 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));
|
||||
}
|
||||
}
|
||||
return instructions.at(index);
|
||||
}
|
||||
|
||||
DWORD TraceFilePage::ThreadId(unsigned long long index) const
|
||||
{
|
||||
return threadId.at(index);
|
||||
|
|
@ -676,3 +716,8 @@ void TraceFilePage::MemoryAccessInfo(unsigned long long index, duint* address, d
|
|||
isValid[i] = true; // proposed flag
|
||||
}
|
||||
}
|
||||
|
||||
void TraceFilePage::updateInstructions()
|
||||
{
|
||||
instructions.clear();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@
|
|||
|
||||
class TraceFileParser;
|
||||
class TraceFilePage;
|
||||
class QBeaEngine;
|
||||
struct Instruction_t;
|
||||
|
||||
#define MAX_MEMORY_OPERANDS 32
|
||||
|
||||
|
|
@ -15,6 +17,7 @@ class TraceFileReader : public QObject
|
|||
Q_OBJECT
|
||||
public:
|
||||
TraceFileReader(QObject* parent = NULL);
|
||||
~TraceFileReader();
|
||||
bool Open(const QString & fileName);
|
||||
void Close();
|
||||
bool Delete();
|
||||
|
|
@ -27,11 +30,12 @@ public:
|
|||
|
||||
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);
|
||||
DWORD ThreadId(unsigned long long index);
|
||||
int MemoryAccessCount(unsigned long long index);
|
||||
void MemoryAccessInfo(unsigned long long index, duint* address, duint* oldMemory, duint* newMemory, bool* isValid);
|
||||
duint HashValue() const;
|
||||
QString ExePath() const;
|
||||
const QString & ExePath() const;
|
||||
|
||||
void purgeLastPage();
|
||||
|
||||
|
|
@ -41,6 +45,9 @@ signals:
|
|||
public slots:
|
||||
void parseFinishedSlot();
|
||||
|
||||
private slots:
|
||||
void tokenizerUpdatedSlot();
|
||||
|
||||
private:
|
||||
typedef std::pair<unsigned long long, unsigned long long> Range;
|
||||
struct RangeCompare //from addrinfo.h
|
||||
|
|
@ -66,6 +73,8 @@ private:
|
|||
TraceFileParser* parser;
|
||||
std::map<Range, TraceFilePage, RangeCompare> pages;
|
||||
TraceFilePage* getPage(unsigned long long index, unsigned long long* base);
|
||||
|
||||
QBeaEngine* mDisasm;
|
||||
};
|
||||
|
||||
#endif //TRACEFILEREADER_H
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
#include <QThread>
|
||||
#include "TraceFileReader.h"
|
||||
#include "QBeaEngine.h"
|
||||
|
||||
class TraceFileParser : public QThread
|
||||
{
|
||||
|
|
@ -16,14 +17,17 @@ class TraceFilePage
|
|||
public:
|
||||
TraceFilePage(TraceFileReader* parent, unsigned long long fileOffset, unsigned long long maxLength);
|
||||
unsigned long long Length() const;
|
||||
REGDUMP Registers(unsigned long long index) 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, QBeaEngine & 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;
|
||||
|
||||
FILETIME lastAccessed; //system user time
|
||||
|
||||
void updateInstructions();
|
||||
|
||||
private:
|
||||
friend class TraceFileReader;
|
||||
TraceFileReader* mParent;
|
||||
|
|
@ -31,6 +35,7 @@ private:
|
|||
QByteArray opcodes;
|
||||
std::vector<size_t> opcodeOffset;
|
||||
std::vector<unsigned char> opcodeSize;
|
||||
std::vector<Instruction_t> instructions;
|
||||
std::vector<size_t> memoryOperandOffset;
|
||||
std::vector<char> memoryFlags;
|
||||
std::vector<duint> memoryAddress;
|
||||
|
|
|
|||
Loading…
Reference in New Issue