1
0
Fork 0

Add copy menu to trace info box

This commit is contained in:
torusrxxx 2021-04-06 22:10:40 +08:00 committed by Duncan Ogilvie
parent 997072a9f6
commit 99822d832b
6 changed files with 402 additions and 330 deletions

View File

@ -0,0 +1,363 @@
#include "TraceInfoBox.h"
#include "TraceWidget.h"
#include "TraceFileReader.h"
#include "CPUInfoBox.h"
#include "zydis_wrapper.h"
TraceInfoBox::TraceInfoBox(TraceWidget* parent) : StdTable(parent)
{
addColumnAt(0, "", true);
setShowHeader(false);
clean();
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setMinimumHeight((getRowHeight() + 1) * 4);
connect(this, SIGNAL(contextMenuSignal(QPoint)), this, SLOT(contextMenuSlot(QPoint)));
// Deselect any row (visual reasons only)
setSingleSelection(-1);
}
TraceInfoBox::~TraceInfoBox()
{
}
void TraceInfoBox::clean()
{
setRowCount(4);
for(int i = 0; i < 4; i++)
setCellContent(i, 0, QString());
}
void TraceInfoBox::update(unsigned long long selection, TraceFileReader* traceFile, const REGDUMP & registers)
{
int infoline = 0;
Zydis zydis;
unsigned char opcode[16];
QString line;
int opsize;
traceFile->OpCode(selection, opcode, &opsize);
clean();
auto resolveRegValue = [&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<ULONG_PTR>(0);
}
};
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);
if(zydis.Disassemble(registers.regcontext.cip, opcode, opsize))
{
int opindex;
int memaccessindex;
//Jumps
if(zydis.IsBranchType(Zydis::BTCondJmp))
{
if(zydis.IsBranchGoingToExecute(registers.regcontext.eflags, registers.regcontext.ccx))
{
line = tr("Jump is taken");
}
else
{
line = tr("Jump is not taken");
}
setCellContent(infoline, 0, line);
infoline++;
}
//Operands
QString registerLine, memoryLine;
for(opindex = 0; opindex < zydis.OpCount(); opindex++)
{
size_t value = zydis.ResolveOpValue(opindex, resolveRegValue);
if(zydis[opindex].type == ZYDIS_OPERAND_TYPE_MEMORY)
{
if(!memoryLine.isEmpty())
memoryLine += ", ";
const char* memsize = zydis.MemSizeName(zydis[opindex].size / 8);
if(memsize != nullptr)
{
memoryLine += memsize;
}
else
{
memoryLine += QString("m%1").arg(zydis[opindex].size / 8);
}
memoryLine += " ptr ";
memoryLine += zydis.RegName(zydis[opindex].mem.segment);
memoryLine += ":[";
memoryLine += ToPtrString(value);
memoryLine += "]";
if(zydis[opindex].size == 64 && zydis.getVectorElementType(opindex) == Zydis::VETFloat64)
{
// Double precision
#ifdef _WIN64
//TODO: Untested
for(memaccessindex = 0; memaccessindex < MemoryOperandsCount; memaccessindex++)
{
if(MemoryAddress[memaccessindex] == value)
{
memoryLine += "= ";
memoryLine += ToDoubleString(&MemoryOldContent[memaccessindex]);
memoryLine += " -> ";
memoryLine += ToDoubleString(&MemoryNewContent[memaccessindex]);
break;
}
}
#else
// On 32-bit platform it is saved as 2 memory accesses.
for(memaccessindex = 0; memaccessindex < MemoryOperandsCount - 1; memaccessindex++)
{
if(MemoryAddress[memaccessindex] == value && MemoryAddress[memaccessindex + 1] == value + 4)
{
double dblval;
memoryLine += "= ";
memcpy(&dblval, &MemoryOldContent[memaccessindex], 4);
memcpy(((char*)&dblval) + 4, &MemoryOldContent[memaccessindex + 1], 4);
memoryLine += ToDoubleString(&dblval);
memoryLine += " -> ";
memcpy(&dblval, &MemoryNewContent[memaccessindex], 4);
memcpy(((char*)&dblval) + 4, &MemoryNewContent[memaccessindex + 1], 4);
memoryLine += ToDoubleString(&dblval);
break;
}
}
#endif //_WIN64
}
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)
{
memoryLine += "= ";
memoryLine += ToFloatString(&MemoryOldContent[memaccessindex]);
memoryLine += " -> ";
memoryLine += ToFloatString(&MemoryNewContent[memaccessindex]);
break;
}
}
}
else if(zydis[opindex].size <= sizeof(void*) * 8)
{
// Handle the most common case (ptr-sized)
duint mask;
if(zydis[opindex].size < sizeof(void*) * 8)
mask = (1 << zydis[opindex].size) - 1;
else
mask = ~(duint)0;
for(memaccessindex = 0; memaccessindex < MemoryOperandsCount; memaccessindex++)
{
if(MemoryAddress[memaccessindex] == value)
{
memoryLine += "=";
memoryLine += ToHexString(MemoryOldContent[memaccessindex] & mask);
memoryLine += " -> ";
memoryLine += ToHexString(MemoryNewContent[memaccessindex] & mask);
break;
}
}
}
}
else if(zydis[opindex].type == ZYDIS_OPERAND_TYPE_REGISTER)
{
const auto registerName = zydis[opindex].reg.value;
if(!registerLine.isEmpty())
registerLine += ", ";
registerLine += zydis.RegName(registerName);
registerLine += " = ";
// Special treatment for FPU registers
if(registerName >= ZYDIS_REGISTER_ST0 && registerName <= ZYDIS_REGISTER_ST7)
{
// x87 FPU
registerLine += ToLongDoubleString(&registers.x87FPURegisters[(registers.x87StatusWordFields.TOP + registerName - ZYDIS_REGISTER_ST0) & 7].data);
}
else if(registerName >= ZYDIS_REGISTER_XMM0 && registerName <= ArchValue(ZYDIS_REGISTER_XMM7, ZYDIS_REGISTER_XMM15))
{
registerLine += CPUInfoBox::formatSSEOperand(QByteArray((const char*)&registers.regcontext.XmmRegisters[registerName - ZYDIS_REGISTER_XMM0], 16), zydis.getVectorElementType(opindex));
}
else if(registerName >= ZYDIS_REGISTER_YMM0 && registerName <= ArchValue(ZYDIS_REGISTER_YMM7, ZYDIS_REGISTER_YMM15))
{
//TODO: Untested
registerLine += CPUInfoBox::formatSSEOperand(QByteArray((const char*)&registers.regcontext.YmmRegisters[registerName - ZYDIS_REGISTER_XMM0], 32), zydis.getVectorElementType(opindex));
}
else
{
// GPR
registerLine += ToPtrString(value);
}
}
}
if(!registerLine.isEmpty())
{
setCellContent(infoline, 0, registerLine);
infoline++;
}
if(!memoryLine.isEmpty())
{
setCellContent(infoline, 0, memoryLine);
infoline++;
}
DWORD tid;
tid = traceFile->ThreadId(selection);
line = QString("ThreadID: %1").arg(ConfigBool("Gui", "PidTidInHex") ? ToHexString(tid) : QString::number(tid));
setCellContent(3, 0, line);
}
reloadData();
}
void TraceInfoBox::setupContextMenu()
{
mCopyLineAction = makeAction(tr("Copy Line"), SLOT(copyLineSlot()));
setupShortcuts();
}
void TraceInfoBox::contextMenuSlot(QPoint pos)
{
QMenu wMenu(this); //create context menu
QMenu wCopyMenu(tr("&Copy"), this);
setupCopyMenu(&wCopyMenu);
wMenu.addMenu(&wCopyMenu);
wMenu.exec(mapToGlobal(pos)); //execute context menu
}
void TraceInfoBox::setupShortcuts()
{
mCopyLineAction->setShortcut(ConfigShortcut("ActionCopyLine"));
addAction(mCopyLineAction);
}

View File

@ -0,0 +1,28 @@
#ifndef TRACEINFOBOX_H
#define TRACEINFOBOX_H
#include "StdTable.h"
class TraceWidget;
class TraceFileReader;
class TraceInfoBox : public StdTable
{
Q_OBJECT
public:
TraceInfoBox(TraceWidget* parent);
~TraceInfoBox();
void update(unsigned long long selection, TraceFileReader* traceFile, const REGDUMP & registers);
public slots:
void contextMenuSlot(QPoint pos);
private:
void setupContextMenu();
void setupShortcuts();
void clean();
QAction* mCopyLineAction;
};
#endif //TRACEINFOBOX_H

View File

@ -1,6 +1,7 @@
#include "TraceWidget.h"
#include "ui_TraceWidget.h"
#include "TraceBrowser.h"
#include "TraceInfoBox.h"
#include "TraceFileReader.h"
#include "TraceRegisters.h"
#include "StdTable.h"
@ -14,7 +15,7 @@ TraceWidget::TraceWidget(QWidget* parent) :
mTraceWidget = new TraceBrowser(this);
mOverview = new StdTable(this);
mInfo = new StdTable(this);
mInfo = new TraceInfoBox(this);
mGeneralRegs = new TraceRegisters(this);
//disasm
ui->mTopLeftUpperRightFrameLayout->addWidget(mTraceWidget);
@ -47,15 +48,6 @@ TraceWidget::TraceWidget(QWidget* parent) :
ui->mTopHSplitter->setSizes(QList<int>({1000, 1}));
ui->mTopLeftVSplitter->setSizes(QList<int>({1000, 1}));
mInfo->addColumnAt(0, "", true);
mInfo->setShowHeader(false);
mInfo->setRowCount(4);
mInfo->setCellContent(0, 0, QString());
mInfo->setCellContent(1, 0, QString());
mInfo->setCellContent(2, 0, QString());
mInfo->setCellContent(3, 0, QString());
mInfo->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
mInfo->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
//overview
ui->mTopRightLowerFrameLayout->addWidget(mOverview);
@ -85,7 +77,7 @@ void TraceWidget::traceSelectionChanged(unsigned long long selection)
if(selection < traceFile->Length())
{
registers = traceFile->Registers(selection);
updateInfobox(selection, traceFile, registers);
mInfo->update(selection, traceFile, registers);
}
else
memset(&registers, 0, sizeof(registers));
@ -102,317 +94,3 @@ TraceBrowser* TraceWidget::getTraceBrowser()
{
return mTraceWidget;
}
void TraceWidget::updateInfobox(unsigned long long selection, TraceFileReader* traceFile, const REGDUMP & registers)
{
int infoline = 0;
Zydis zydis;
unsigned char opcode[16];
QString line;
int opsize;
traceFile->OpCode(selection, opcode, &opsize);
mInfo->setRowCount(4);
mInfo->setCellContent(0, 0, QString());
mInfo->setCellContent(1, 0, QString());
mInfo->setCellContent(2, 0, QString());
mInfo->setCellContent(3, 0, QString());
auto resolveRegValue = [&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<ULONG_PTR>(0);
}
};
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);
if(zydis.Disassemble(registers.regcontext.cip, opcode, opsize))
{
int opindex;
int memaccessindex;
//Jumps
if(zydis.IsBranchType(Zydis::BTCondJmp))
{
if(zydis.IsBranchGoingToExecute(registers.regcontext.eflags, registers.regcontext.ccx))
{
line = tr("Jump is taken");
}
else
{
line = tr("Jump is not taken");
}
mInfo->setCellContent(infoline, 0, line);
infoline++;
}
//Operands
QString registerLine, memoryLine;
for(opindex = 0; opindex < zydis.OpCount(); opindex++)
{
size_t value = zydis.ResolveOpValue(opindex, resolveRegValue);
if(zydis[opindex].type == ZYDIS_OPERAND_TYPE_MEMORY)
{
if(!memoryLine.isEmpty())
memoryLine += ", ";
const char* memsize = zydis.MemSizeName(zydis[opindex].size / 8);
if(memsize != nullptr)
{
memoryLine += memsize;
}
else
{
memoryLine += QString("m%1").arg(zydis[opindex].size / 8);
}
memoryLine += " ptr ";
memoryLine += zydis.RegName(zydis[opindex].mem.segment);
memoryLine += ":[";
memoryLine += ToPtrString(value);
memoryLine += "]";
if(zydis[opindex].size == 64 && zydis.getVectorElementType(opindex) == Zydis::VETFloat64)
{
// Double precision
#ifdef _WIN64
//TODO: Untested
for(memaccessindex = 0; memaccessindex < MemoryOperandsCount; memaccessindex++)
{
if(MemoryAddress[memaccessindex] == value)
{
memoryLine += "= ";
memoryLine += ToDoubleString(&MemoryOldContent[memaccessindex]);
memoryLine += " -> ";
memoryLine += ToDoubleString(&MemoryNewContent[memaccessindex]);
break;
}
}
#else
// On 32-bit platform it is saved as 2 memory accesses.
for(memaccessindex = 0; memaccessindex < MemoryOperandsCount - 1; memaccessindex++)
{
if(MemoryAddress[memaccessindex] == value && MemoryAddress[memaccessindex + 1] == value + 4)
{
double dblval;
memoryLine += "= ";
memcpy(&dblval, &MemoryOldContent[memaccessindex], 4);
memcpy(((char*)&dblval) + 4, &MemoryOldContent[memaccessindex + 1], 4);
memoryLine += ToDoubleString(&dblval);
memoryLine += " -> ";
memcpy(&dblval, &MemoryNewContent[memaccessindex], 4);
memcpy(((char*)&dblval) + 4, &MemoryNewContent[memaccessindex + 1], 4);
memoryLine += ToDoubleString(&dblval);
break;
}
}
#endif //_WIN64
}
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)
{
memoryLine += "= ";
memoryLine += ToFloatString(&MemoryOldContent[memaccessindex]);
memoryLine += " -> ";
memoryLine += ToFloatString(&MemoryNewContent[memaccessindex]);
break;
}
}
}
else if(zydis[opindex].size <= sizeof(void*) * 8)
{
// Handle the most common case (ptr-sized)
duint mask;
if(zydis[opindex].size < sizeof(void*) * 8)
mask = (1 << zydis[opindex].size) - 1;
else
mask = ~(duint)0;
for(memaccessindex = 0; memaccessindex < MemoryOperandsCount; memaccessindex++)
{
if(MemoryAddress[memaccessindex] == value)
{
memoryLine += "=";
memoryLine += ToHexString(MemoryOldContent[memaccessindex] & mask);
memoryLine += " -> ";
memoryLine += ToHexString(MemoryNewContent[memaccessindex] & mask);
break;
}
}
}
}
else if(zydis[opindex].type == ZYDIS_OPERAND_TYPE_REGISTER)
{
const auto registerName = zydis[opindex].reg.value;
if(!registerLine.isEmpty())
registerLine += ", ";
registerLine += zydis.RegName(registerName);
registerLine += " = ";
// Special treatment for FPU registers
if(registerName >= ZYDIS_REGISTER_ST0 && registerName <= ZYDIS_REGISTER_ST7)
{
// x87 FPU
registerLine += ToLongDoubleString(&registers.x87FPURegisters[(registers.x87StatusWordFields.TOP + registerName - ZYDIS_REGISTER_ST0) & 7].data);
}
else if(registerName >= ZYDIS_REGISTER_XMM0 && registerName <= ArchValue(ZYDIS_REGISTER_XMM7, ZYDIS_REGISTER_XMM15))
{
registerLine += CPUInfoBox::formatSSEOperand(QByteArray((const char*)&registers.regcontext.XmmRegisters[registerName - ZYDIS_REGISTER_XMM0], 16), zydis.getVectorElementType(opindex));
}
else if(registerName >= ZYDIS_REGISTER_YMM0 && registerName <= ArchValue(ZYDIS_REGISTER_YMM7, ZYDIS_REGISTER_YMM15))
{
//TODO: Untested
registerLine += CPUInfoBox::formatSSEOperand(QByteArray((const char*)&registers.regcontext.YmmRegisters[registerName - ZYDIS_REGISTER_XMM0], 32), zydis.getVectorElementType(opindex));
}
else
{
// GPR
registerLine += ToPtrString(value);
}
}
}
if(!registerLine.isEmpty())
{
mInfo->setCellContent(infoline, 0, registerLine);
infoline++;
}
if(!memoryLine.isEmpty())
{
mInfo->setCellContent(infoline, 0, memoryLine);
infoline++;
}
DWORD tid;
tid = traceFile->ThreadId(selection);
line = QString("ThreadID: %1").arg(ConfigBool("Gui", "PidTidInHex") ? ToHexString(tid) : QString::number(tid));
mInfo->setCellContent(3, 0, line);
}
mInfo->reloadData();
}

View File

@ -9,6 +9,7 @@ class CPUWidget;
class TraceRegisters;
class TraceBrowser;
class TraceFileReader;
class TraceInfoBox;
class StdTable;
namespace Ui
@ -32,12 +33,10 @@ protected slots:
protected:
TraceBrowser* mTraceWidget;
TraceInfoBox* mInfo;
TraceRegisters* mGeneralRegs;
StdTable* mInfo;
StdTable* mOverview;
void updateInfobox(unsigned long long selection, TraceFileReader* traceFile, const REGDUMP & registers);
private:
Ui::TraceWidget* ui;
};

View File

@ -79,6 +79,7 @@ SOURCES += \
Src/Gui/CPURegistersView.cpp \
Src/Gui/SystemBreakpointScriptDialog.cpp \
Src/Imports.cpp \
Src/Tracer/TraceInfoBox.cpp \
Src/Tracer/TraceRegisters.cpp \
Src/Tracer/TraceWidget.cpp \
Src/Utils/CommonActions.cpp \
@ -199,6 +200,7 @@ HEADERS += \
Src/BasicView/StdIconTable.h \
Src/Gui/CPURegistersView.h \
Src/Gui/SystemBreakpointScriptDialog.h \
Src/Tracer/TraceInfoBox.h \
Src/Tracer/TraceRegisters.h \
Src/Tracer/TraceWidget.h \
Src/Utils/CommonActions.h \

View File

@ -229,7 +229,8 @@ SOURCES += \
gui/Src/Gui/CPURegistersView.cpp \
gui/Src/Tracer/TraceRegisters.cpp \
gui/Src/Tracer/TraceWidget.cpp \
gui/Src/Gui/SystemBreakpointScriptDialog.cpp
gui/Src/Gui/SystemBreakpointScriptDialog.cpp \
gui/Src/Tracer/TraceInfoBox.cpp
HEADERS += \
gui/Src/Exports.h \
@ -470,7 +471,8 @@ HEADERS += \
gui/Src/Gui/CPURegistersView.h \
gui/Src/Tracer/TraceRegisters.h \
gui/Src/Tracer/TraceWidget.h \
gui/Src/Gui/SystemBreakpointScriptDialog.h
gui/Src/Gui/SystemBreakpointScriptDialog.h \
gui/Src/Tracer/TraceInfoBox.h
FORMS += \
gui/Src/Gui/AppearanceDialog.ui \