1
0
Fork 0

Cache disassembly in trace file reader

This commit is contained in:
torusrxxx 2020-07-22 23:07:38 +08:00 committed by Duncan Ogilvie
parent 220e1d0902
commit 35c6516df9
7 changed files with 89 additions and 58 deletions

View File

@ -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;

View File

@ -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();

View File

@ -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);
}

View File

@ -77,7 +77,6 @@ private:
bool mAutoDisassemblyFollowSelection;
TraceFileReader* mTraceFile;
QBeaEngine* mDisasm;
BreakpointMenu* mBreakpointMenu;
MRUList* mMRUList;
QString mFileName;

View File

@ -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();
}

View File

@ -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

View File

@ -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;