mirror of
https://github.com/x64dbg/x64dbg.git
synced 2024-11-26 22:30:22 +00:00
enhance the FPU support for trace info box and trace registers view
This commit is contained in:
parent
ba891068dd
commit
a0ca41465e
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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?)
|
||||
}
|
||||
|
@ -15,6 +15,9 @@ public slots:
|
||||
virtual void displayCustomContextMenuSlot(QPoint pos);
|
||||
void onCopySIMDRegister();
|
||||
|
||||
protected:
|
||||
virtual void mouseDoubleClickEvent(QMouseEvent* event);
|
||||
|
||||
private:
|
||||
QAction* wCM_CopySIMDRegister;
|
||||
};
|
||||
|
@ -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(®isters.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*)®isters.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*)®isters.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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user