enhance the FPU support for trace info box and trace registers view

This commit is contained in:
torusrxxx 2021-03-31 20:43:47 +08:00
parent ba891068dd
commit a0ca41465e
No known key found for this signature in database
GPG Key ID: A795C73A0F1CFADD
9 changed files with 167 additions and 60 deletions

View File

@ -91,7 +91,7 @@ void CPUInfoBox::clear()
setInfoLine(3, "");
}
static QString formatSSEOperand(const QByteArray & data, uint8_t vectorType)
QString CPUInfoBox::formatSSEOperand(const QByteArray & data, uint8_t vectorType)
{
QString hex;
bool isXMMdecoded = false;

View File

@ -22,6 +22,8 @@ public:
void setupWatchMenu(QMenu* menu, duint wVA);
int followInDump(dsint wVA);
static QString formatSSEOperand(const QByteArray & data, uint8_t vectorType);
public slots:
void disasmSelectionChanged(dsint parVA);
void dbgStateChanged(DBGSTATE state);

View File

@ -222,6 +222,17 @@ extern STRING_VALUE_TABLE_t TagWordValueStringTable[4];
#define MODIFY_FIELDS_DISPLAY(prefix, title, table) ModifyFields(prefix + QChar(' ') + QString(title), (STRING_VALUE_TABLE_t *) & table, SIZE_TABLE(table) )
static void editSIMDRegister(CPURegistersView* parent, int bits, const QString & title, char* data, RegistersView::REGISTER_NAME mSelected)
{
EditFloatRegister mEditFloat(bits, parent);
mEditFloat.setWindowTitle(title);
mEditFloat.loadData(data);
mEditFloat.show();
mEditFloat.selectAllText();
if(mEditFloat.exec() == QDialog::Accepted)
parent->setRegister(mSelected, (duint)mEditFloat.getData());
}
/**
* @brief This function displays the appropriate edit dialog according to selected register
* @return Nothing.
@ -246,35 +257,11 @@ void CPURegistersView::displayEditDialog()
updateRegistersSlot();
}
else if(mFPUYMM.contains(mSelected))
{
EditFloatRegister mEditFloat(256, this);
mEditFloat.setWindowTitle(tr("Edit YMM register"));
mEditFloat.loadData(registerValue(&wRegDumpStruct, mSelected));
mEditFloat.show();
mEditFloat.selectAllText();
if(mEditFloat.exec() == QDialog::Accepted)
setRegister(mSelected, (duint)mEditFloat.getData());
}
editSIMDRegister(this, 256, tr("Edit YMM register"), registerValue(&wRegDumpStruct, mSelected), mSelected);
else if(mFPUXMM.contains(mSelected))
{
EditFloatRegister mEditFloat(128, this);
mEditFloat.setWindowTitle(tr("Edit XMM register"));
mEditFloat.loadData(registerValue(&wRegDumpStruct, mSelected));
mEditFloat.show();
mEditFloat.selectAllText();
if(mEditFloat.exec() == QDialog::Accepted)
setRegister(mSelected, (duint)mEditFloat.getData());
}
editSIMDRegister(this, 128, tr("Edit XMM register"), registerValue(&wRegDumpStruct, mSelected), mSelected);
else if(mFPUMMX.contains(mSelected))
{
EditFloatRegister mEditFloat(64, this);
mEditFloat.setWindowTitle(tr("Edit MMX register"));
mEditFloat.loadData(registerValue(&wRegDumpStruct, mSelected));
mEditFloat.show();
mEditFloat.selectAllText();
if(mEditFloat.exec() == QDialog::Accepted)
setRegister(mSelected, (duint)mEditFloat.getData());
}
editSIMDRegister(this, 64, tr("Edit MMX register"), registerValue(&wRegDumpStruct, mSelected), mSelected);
else
{
bool errorinput = false;

View File

@ -223,7 +223,7 @@ void EditFloatRegister::hideNonMMXPart()
* @param[in] RegisterData the data to be loaded. It must be at lease the same size as the size specified in RegisterSize
* @return Nothing.
*/
void EditFloatRegister::loadData(char* RegisterData)
void EditFloatRegister::loadData(const char* RegisterData)
{
memcpy(Data, RegisterData, RegSize / 8);
reloadDataLow();
@ -234,7 +234,7 @@ void EditFloatRegister::loadData(char* RegisterData)
* @brief Get the register data from the dialog
* @return The output buffer.
*/
const char* EditFloatRegister::getData()
const char* EditFloatRegister::getData() const
{
return Data;
}

View File

@ -18,8 +18,8 @@ class EditFloatRegister : public QDialog
public:
explicit EditFloatRegister(int RegisterSize, QWidget* parent = 0);
void loadData(char* RegisterData);
const char* getData();
void loadData(const char* RegisterData);
const char* getData() const;
void selectAllText();
~EditFloatRegister();

View File

@ -917,10 +917,10 @@ void TraceBrowser::setupRightClickContextMenu()
menu->addAction(QString("%1: %2 -> %3").arg(getAddrText(MemoryAddress[i], nolabel, false)).arg(ToPtrString(MemoryOldContent[i])).arg(ToPtrString(MemoryNewContent[i])));
}
mRvaDisplayEnabled = RvaDisplayEnabled;
menu->addSeparator();
return true;
}
menu->addAction(QString("ThreadID: %1").arg(mTraceFile->ThreadId(index)));
return true;
else
return false; //The information menu now only contains memory access info
});
mMenuBuilder->addMenu(makeMenu(tr("Information")), infoMenu);

View File

@ -1,6 +1,8 @@
#include <QMouseEvent>
#include "TraceRegisters.h"
#include "Configuration.h"
#include "EditFloatRegister.h"
#include "StringUtil.h"
#include "MiscUtil.h"
TraceRegisters::TraceRegisters(QWidget* parent) : RegistersView(parent)
@ -64,7 +66,7 @@ void TraceRegisters::displayCustomContextMenuSlot(QPoint pos)
wMenu.exec(this->mapToGlobal(pos));
}
else
else // Right-click on empty space
{
wMenu.addSeparator();
wMenu.addAction(wCM_ChangeFPUView);
@ -98,3 +100,22 @@ void TraceRegisters::onCopySIMDRegister()
else if(mFPUMMX.contains(mSelected))
showCopyFloatRegister(64, this, tr("View MMX register"), registerValue(&wRegDumpStruct, mSelected));
}
void TraceRegisters::mouseDoubleClickEvent(QMouseEvent* event)
{
if(!isActive || event->button() != Qt::LeftButton)
return;
// get mouse position
const int y = (event->y() - yTopSpacing) / (double)mRowHeight;
const int x = event->x() / (double)mCharWidth;
// do we find a corresponding register?
if(!identifyRegister(y, x, 0))
return;
if(mSelected == CIP) //double clicked on CIP register: follow in disassembly
DbgCmdExec(QString("disasm %1").arg(ToPtrString(wRegDumpStruct.regcontext.cip)));
// double clicked on XMM register: open view XMM register dialog
else if(mFPUXMM.contains(mSelected) || mFPUYMM.contains(mSelected) || mFPUMMX.contains(mSelected))
onCopySIMDRegister();
// double clicked on GPR: nothing to do (copy?)
}

View File

@ -15,6 +15,9 @@ public slots:
virtual void displayCustomContextMenuSlot(QPoint pos);
void onCopySIMDRegister();
protected:
virtual void mouseDoubleClickEvent(QMouseEvent* event);
private:
QAction* wCM_CopySIMDRegister;
};

View File

@ -4,6 +4,7 @@
#include "TraceFileReader.h"
#include "TraceRegisters.h"
#include "StdTable.h"
#include "CPUInfoBox.h"
TraceWidget::TraceWidget(QWidget* parent) :
QWidget(parent),
@ -53,6 +54,8 @@ TraceWidget::TraceWidget(QWidget* parent) :
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);
@ -272,53 +275,144 @@ void TraceWidget::updateInfobox(unsigned long long selection, TraceFileReader* t
infoline++;
}
//Operands
QString registerLine, memoryLine;
for(opindex = 0; opindex < zydis.OpCount(); opindex++)
{
line.clear();
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)
{
line += memsize;
memoryLine += memsize;
}
line += " ptr ";
line += zydis.RegName(zydis[opindex].mem.segment);
line += ":[";
line += ToPtrString(value);
line += "]";
if(zydis[opindex].size <= sizeof(void*) * 8)
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)
{
line += "=";
duint mask;
if(zydis[opindex].size < sizeof(void*) * 8)
mask = (1 << zydis[opindex].size) - 1;
else
mask = ~(duint)0;
line += ToHexString(MemoryOldContent[memaccessindex] & mask);
line += " -> ";
line += ToHexString(MemoryNewContent[memaccessindex] & mask);
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;
}
}
}
mInfo->setCellContent(infoline, 0, line);
infoline++;
}
else if(zydis[opindex].type == ZYDIS_OPERAND_TYPE_REGISTER)
{
line += zydis.RegName(zydis[opindex].reg.value);
line += " = ";
line += ToPtrString(value);
mInfo->setCellContent(infoline, 0, line);
infoline++;
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();
}