1
0
Fork 0

Merge pull request #2627 from torusrxxx/patch000000bb

UI improvements
This commit is contained in:
Duncan Ogilvie 2021-04-16 10:39:36 +02:00 committed by GitHub
commit d084dc48a5
Signed by: GitHub
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 589 additions and 480 deletions

View File

@ -112,6 +112,8 @@ void CPUWidget::saveWindowSettings()
saveSplitter(ui->mVSplitter, "mVSplitter");
saveSplitter(ui->mTopHSplitter, "mTopHSplitter");
saveSplitter(ui->mTopLeftVSplitter, "mTopLeftVSplitter");
if(disasMode == 1 && mDisasmSidebarSplitterStatus.size() > 0) // restore correct sidebar state
ui->mTopLeftUpperHSplitter->restoreState(mDisasmSidebarSplitterStatus);
saveSplitter(ui->mTopLeftUpperHSplitter, "mTopLeftUpperHSplitter");
saveSplitter(ui->mTopRightVSplitter, "mTopRightVSplitter");
saveSplitter(ui->mBotHSplitter, "mBotHSplitter");
@ -169,6 +171,7 @@ void CPUWidget::setDisasmFocus()
mGraph->hide();
mDisas->show();
mSideBar->show();
ui->mTopLeftUpperHSplitter->restoreState(mDisasmSidebarSplitterStatus);
disasMode = 0;
connect(mDisas, SIGNAL(selectionChanged(dsint)), mInfo, SLOT(disasmSelectionChanged(dsint)));
disconnect(mGraph, SIGNAL(selectionChanged(dsint)), mInfo, SLOT(disasmSelectionChanged(dsint)));
@ -184,9 +187,12 @@ void CPUWidget::setGraphFocus()
{
if(disasMode == 0)
{
mDisasmSidebarSplitterStatus = ui->mTopLeftUpperHSplitter->saveState();
mDisas->hide();
mSideBar->hide();
mGraph->show();
// Hide the sidebar area
ui->mTopLeftUpperHSplitter->setSizes(QList<int>({0, 100}));
disasMode = 1;
disconnect(mDisas, SIGNAL(selectionChanged(dsint)), mInfo, SLOT(disasmSelectionChanged(dsint)));
connect(mGraph, SIGNAL(selectionChanged(dsint)), mInfo, SLOT(disasmSelectionChanged(dsint)));
@ -235,6 +241,8 @@ void CPUWidget::detachGraph()
mDisas->show();
mSideBar->show();
// restore the sidebar splitter so that the sidebar is visible
ui->mTopLeftUpperHSplitter->restoreState(mDisasmSidebarSplitterStatus);
connect(mDisas, SIGNAL(selectionChanged(dsint)), mInfo, SLOT(disasmSelectionChanged(dsint)));
connect(mGraph, SIGNAL(selectionChanged(dsint)), mInfo, SLOT(disasmSelectionChanged(dsint)));
}

View File

@ -63,6 +63,7 @@ protected:
private:
Ui::CPUWidget* ui;
QByteArray mDisasmSidebarSplitterStatus;
private slots:
void splitterMoved(int pos, int index);

View File

@ -17,117 +17,130 @@
<iconset resource="../../resource.qrc">
<normaloff>:/icons/images/patch.png</normaloff>:/icons/images/patch.png</iconset>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QVBoxLayout" name="layoutModules">
<item>
<widget class="QGroupBox" name="groupModules">
<property name="title">
<string>&amp;Modules</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QListWidget" name="listModules">
<property name="font">
<font>
<family>Courier New</family>
</font>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<widget class="QSplitter" name="splitter">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="handleWidth">
<number>1</number>
</property>
<property name="childrenCollapsible">
<bool>false</bool>
</property>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="layoutModules">
<item>
<widget class="QPushButton" name="btnImport">
<property name="text">
<string>&amp;Import</string>
<widget class="QGroupBox" name="groupModules">
<property name="title">
<string>&amp;Modules</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QListWidget" name="listModules">
<property name="font">
<font>
<family>Courier New</family>
</font>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnExport">
<property name="text">
<string>&amp;Export</string>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QPushButton" name="btnImport">
<property name="text">
<string>&amp;Import</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnExport">
<property name="text">
<string>&amp;Export</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="layoutPatches">
<item>
<widget class="QGroupBox" name="groupPatches">
<property name="title">
<string>P&amp;atches</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QListWidget" name="listPatches">
<property name="font">
<font>
<family>Courier New</family>
</font>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
</widget>
<widget class="QWidget" name="layoutWidget">
<layout class="QVBoxLayout" name="layoutPatches">
<item>
<widget class="QPushButton" name="btnSelectAll">
<property name="text">
<string>&amp;Select All</string>
<widget class="QGroupBox" name="groupPatches">
<property name="title">
<string>P&amp;atches</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QListWidget" name="listPatches">
<property name="font">
<font>
<family>Courier New</family>
</font>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDeselectAll">
<property name="text">
<string>&amp;Deselect All</string>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="btnSelectAll">
<property name="text">
<string>&amp;Select All</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnDeselectAll">
<property name="text">
<string>&amp;Deselect All</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnRestoreSelected">
<property name="text">
<string>&amp;Restore Selected</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="btnRestoreSelected">
<property name="text">
<string>&amp;Restore Selected</string>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="btnPickGroups">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Pick &amp;Groups</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnPatchFile">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Patch File</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<widget class="QPushButton" name="btnPickGroups">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>Pick &amp;Groups</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnPatchFile">
<property name="enabled">
<bool>true</bool>
</property>
<property name="text">
<string>&amp;Patch File</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</widget>
@ -135,12 +148,6 @@
<tabstop>listModules</tabstop>
<tabstop>btnImport</tabstop>
<tabstop>btnExport</tabstop>
<tabstop>listPatches</tabstop>
<tabstop>btnSelectAll</tabstop>
<tabstop>btnDeselectAll</tabstop>
<tabstop>btnRestoreSelected</tabstop>
<tabstop>btnPickGroups</tabstop>
<tabstop>btnPatchFile</tabstop>
</tabstops>
<resources>
<include location="../../resource.qrc"/>

View File

@ -635,28 +635,43 @@ void SymbolView::moduleEntryFollow()
void SymbolView::moduleCopyPath()
{
duint modbase = DbgValFromString(mModuleList->mCurList->getCellContent(mModuleList->mCurList->getInitialSelection(), ColBase).toUtf8().constData());
char szModPath[MAX_PATH] = "";
if(DbgFunctions()->ModPathFromAddr(modbase, szModPath, _countof(szModPath)))
Bridge::CopyToClipboard(szModPath);
QString modulePaths;
auto selection = mModuleList->mCurList->getSelection();
for(auto i : selection)
{
duint modbase = DbgValFromString(mModuleList->mCurList->getCellContent(i, ColBase).toUtf8().constData());
char szModPath[MAX_PATH] = "";
if(!DbgFunctions()->ModPathFromAddr(modbase, szModPath, _countof(szModPath)))
memcpy(szModPath, "???", 4);
if(!modulePaths.isEmpty())
modulePaths.append("\r\n");
modulePaths.append(szModPath);
}
Bridge::CopyToClipboard(modulePaths);
}
void SymbolView::moduleBrowse()
{
duint modbase = DbgValFromString(mModuleList->mCurList->getCellContent(mModuleList->mCurList->getInitialSelection(), ColBase).toUtf8().constData());
char szModPath[MAX_PATH] = "";
if(DbgFunctions()->ModPathFromAddr(modbase, szModPath, _countof(szModPath)))
auto selection = mModuleList->mCurList->getSelection();
for(auto i : selection)
{
QStringList arguments;
arguments << QString("/select,");
arguments << QString(szModPath);
QProcess::startDetached(QString("%1/explorer.exe").arg(QProcessEnvironment::systemEnvironment().value("windir")), arguments);
duint modbase = DbgValFromString(mModuleList->mCurList->getCellContent(i, ColBase).toUtf8().constData());
char szModPath[MAX_PATH] = "";
if(DbgFunctions()->ModPathFromAddr(modbase, szModPath, _countof(szModPath)))
{
QStringList arguments;
arguments << QString("/select,");
arguments << QString(szModPath);
QProcess::startDetached(QString("%1/explorer.exe").arg(QProcessEnvironment::systemEnvironment().value("windir")), arguments);
}
}
}
void SymbolView::moduleDownloadSymbols()
{
DbgCmdExec(QString("symdownload \"%0\"").arg(mModuleList->mCurList->getCellContent(mModuleList->mCurList->getInitialSelection(), ColModule)));
auto selection = mModuleList->mCurList->getSelection();
for(auto i : selection)
DbgCmdExec(QString("symdownload \"%0\"").arg(mModuleList->mCurList->getCellContent(i, ColModule)));
}
void SymbolView::moduleDownloadAllSymbols()
@ -691,7 +706,11 @@ void SymbolView::moduleFree()
question.toUtf8().constData(),
QMessageBox::Yes | QMessageBox::No);
if(reply == QMessageBox::Yes)
DbgCmdExec(QString("freelib %1").arg(mModuleList->mCurList->getCellContent(mModuleList->mCurList->getInitialSelection(), ColBase)));
{
auto selection = mModuleList->mCurList->getSelection();
for(auto module : selection)
DbgCmdExec(QString("freelib %1").arg(mModuleList->mCurList->getCellContent(module, ColBase)));
}
}
}
@ -742,42 +761,53 @@ void SymbolView::toggleBookmark()
if(!mSymbolList->mCurList->getRowCount())
return;
QString addrText = mSymbolList->mCurList->getCellContent(mSymbolList->mCurList->getInitialSelection(), 0);
duint wVA;
if(!DbgFunctions()->ValFromString(addrText.toUtf8().constData(), &wVA))
return;
if(!DbgMemIsValidReadPtr(wVA))
return;
bool result;
if(DbgGetBookmarkAt(wVA))
result = DbgSetBookmarkAt(wVA, false);
else
result = DbgSetBookmarkAt(wVA, true);
if(!result)
auto selection = mSymbolList->mCurList->getSelection();
for(auto index : selection)
{
QMessageBox msg(QMessageBox::Critical, tr("Error!"), tr("DbgSetBookmarkAt failed!"));
msg.setWindowIcon(DIcon("compile-error.png"));
msg.setParent(this, Qt::Dialog);
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
msg.exec();
QString addrText = mSymbolList->mCurList->getCellContent(index, 0);
duint wVA;
if(!DbgFunctions()->ValFromString(addrText.toUtf8().constData(), &wVA))
return;
if(!DbgMemIsValidReadPtr(wVA))
return;
bool result;
if(DbgGetBookmarkAt(wVA))
result = DbgSetBookmarkAt(wVA, false);
else
result = DbgSetBookmarkAt(wVA, true);
if(!result)
{
QMessageBox msg(QMessageBox::Critical, tr("Error!"), tr("DbgSetBookmarkAt failed!"));
msg.setWindowIcon(DIcon("compile-error.png"));
msg.setParent(this, Qt::Dialog);
msg.setWindowFlags(msg.windowFlags() & (~Qt::WindowContextHelpButtonHint));
msg.exec();
}
}
GuiUpdateAllViews();
}
void SymbolView::moduleSetSystem()
{
int i = mModuleList->mCurList->getInitialSelection();
duint modbase = DbgValFromString(mModuleList->mCurList->getCellContent(i, ColBase).toUtf8().constData());
DbgFunctions()->ModSetParty(modbase, mod_system);
auto selection = mModuleList->mCurList->getSelection();
for(auto i : selection)
{
duint modbase = DbgValFromString(mModuleList->mCurList->getCellContent(i, ColBase).toUtf8().constData());
DbgFunctions()->ModSetParty(modbase, mod_system);
}
DbgFunctions()->RefreshModuleList();
}
void SymbolView::moduleSetUser()
{
int i = mModuleList->mCurList->getInitialSelection();
duint modbase = DbgValFromString(mModuleList->mCurList->getCellContent(i, ColBase).toUtf8().constData());
DbgFunctions()->ModSetParty(modbase, mod_user);
auto selection = mModuleList->mCurList->getSelection();
for(auto i : selection)
{
duint modbase = DbgValFromString(mModuleList->mCurList->getCellContent(i, ColBase).toUtf8().constData());
DbgFunctions()->ModSetParty(modbase, mod_user);
}
DbgFunctions()->RefreshModuleList();
}
@ -792,27 +822,18 @@ void SymbolView::moduleSetParty()
{
bool ok;
party = mLineEditeditText.toInt(&ok);
int i = mModuleList->mCurList->getInitialSelection();
if(ok)
{
DbgFunctions()->ModSetParty(modbase, (MODULEPARTY)party);
/* TODO: refresh module list
switch(party)
auto selection = mModuleList->mCurList->getSelection();
for(auto index : selection)
{
case 0:
mModuleList->mCurList->setCellContent(i, 2, tr("User"));
break;
case 1:
mModuleList->mCurList->setCellContent(i, 2, tr("System"));
break;
default:
mModuleList->mCurList->setCellContent(i, 2, tr("Party: %1").arg(party));
break;
modbase = DbgValFromString(mModuleList->mCurList->getCellContent(index, ColBase).toUtf8().constData());
DbgFunctions()->ModSetParty(modbase, (MODULEPARTY)party);
}
mModuleList->mCurList->reloadData();*/
}
else
SimpleErrorBox(this, tr("Error"), tr("The party number can only be 0 or 1"));
DbgFunctions()->RefreshModuleList();
}
}

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 \