1
0
Fork 0
x64dbg/x64_dbg_gui/Project/Src/BasicView/HexDump.cpp

949 lines
21 KiB
C++

#include "HexDump.h"
#include "Configuration.h"
HexDump::HexDump(QWidget *parent) : AbstractTableView(parent)
{
fontsUpdated();
SelectionData_t data;
memset(&data, 0, sizeof(SelectionData_t));
mSelection = data;
mGuiState = HexDump::NoState;
setRowCount(0);
mMemPage = new MemoryPage(0, 0);
clearDescriptors();
backgroundColor=ConfigColor("HexDumpBackgroundColor");
textColor=ConfigColor("HexDumpTextColor");
selectionColor=ConfigColor("HexDumpSelectionColor");
connect(Bridge::getBridge(), SIGNAL(updateDump()), this, SLOT(reloadData()));
connect(Bridge::getBridge(), SIGNAL(dbgStateChanged(DBGSTATE)), this, SLOT(debugStateChanged(DBGSTATE)));
}
void HexDump::colorsUpdated()
{
AbstractTableView::colorsUpdated();
backgroundColor=ConfigColor("HexDumpBackgroundColor");
textColor=ConfigColor("HexDumpTextColor");
selectionColor=ConfigColor("HexDumpSelectionColor");
reloadData();
}
void HexDump::fontsUpdated()
{
setFont(ConfigFont("HexDump"));
}
void HexDump::printDumpAt(int_t parVA, bool select)
{
int_t wBase = DbgMemFindBaseAddr(parVA, 0); //get memory base
int_t wSize = DbgMemGetPageSize(wBase); //get page size
if(!wBase || !wSize)
return;
int_t wRVA = parVA - wBase; //calculate rva
int wBytePerRowCount = getBytePerRowCount(); //get the number of bytes per row
int_t wRowCount;
// Byte offset used to be aligned on the given RVA
mByteOffset = (int)((int_t)wRVA % (int_t)wBytePerRowCount);
mByteOffset = mByteOffset > 0 ? wBytePerRowCount - mByteOffset : 0;
// Compute row count
wRowCount = wSize / wBytePerRowCount;
wRowCount += mByteOffset > 0 ? 1 : 0;
setRowCount(wRowCount); //set the number of rows
mMemPage->setAttributes(wBase, wSize); // Set base and size (Useful when memory page changed)
setTableOffset(-1); //make sure the requested address is always first
setTableOffset((wRVA + mByteOffset) / wBytePerRowCount); //change the displayed offset
if(select)
{
setSingleSelection(wRVA);
int_t wEndingAddress = wRVA + getSizeOf(mDescriptor.at(0).data.itemSize) - 1;
expandSelectionUpTo(wEndingAddress);
}
reloadData();
}
void HexDump::printDumpAt(int_t parVA)
{
printDumpAt(parVA, true);
}
uint_t HexDump::rvaToVa(int_t rva)
{
return mMemPage->va(rva);
}
void HexDump::mouseMoveEvent(QMouseEvent* event)
{
bool wAccept = true;
if(mGuiState == HexDump::MultiRowsSelectionState)
{
//qDebug() << "State = MultiRowsSelectionState";
if((transY(event->y()) >= 0) && event->y() <= this->height())
{
for(int wI = 1; wI < getColumnCount(); wI++) // Skip first column (Addresses)
{
int wColIndex = getColumnIndexFromX(event->x());
if(wColIndex > 0) // No selection for first column (addresses)
{
int_t wStartingAddress = getItemStartingAddress(event->x(), event->y());
int_t wEndingAddress = wStartingAddress + getSizeOf(mDescriptor.at(wColIndex - 1).data.itemSize) - 1;
if(wEndingAddress < (int_t)mMemPage->getSize())
{
if(wStartingAddress < getInitialSelection())
expandSelectionUpTo(wStartingAddress);
else
expandSelectionUpTo(wEndingAddress);
mGuiState = HexDump::MultiRowsSelectionState;
repaint();
}
}
}
wAccept = true;
}
}
if(wAccept == true)
AbstractTableView::mouseMoveEvent(event);
}
void HexDump::mousePressEvent(QMouseEvent* event)
{
//qDebug() << "HexDump::mousePressEvent";
bool wAccept = false;
if(((event->buttons() & Qt::LeftButton) != 0) && ((event->buttons() & Qt::RightButton) == 0))
{
if(getGuiState() == AbstractTableView::NoState)
{
if(event->y() > getHeaderHeight() && event->y() <= this->height())
{
int wColIndex = getColumnIndexFromX(event->x());
for(int wI = 1; wI < getColumnCount(); wI++) // Skip first column (Addresses)
{
if(wColIndex > 0 && mDescriptor.at(wColIndex - 1).isData == true) // No selection for first column (addresses) and no data columns
{
int_t wStartingAddress = getItemStartingAddress(event->x(), event->y());
int_t wEndingAddress = wStartingAddress + getSizeOf(mDescriptor.at(wColIndex - 1).data.itemSize) - 1;
if(wEndingAddress < (int_t)mMemPage->getSize())
{
if(!(event->modifiers() & Qt::ShiftModifier))
setSingleSelection(wStartingAddress);
expandSelectionUpTo(wEndingAddress);
mGuiState = HexDump::MultiRowsSelectionState;
repaint();
}
}
}
wAccept = true;
}
}
}
if(wAccept == false)
AbstractTableView::mousePressEvent(event);
}
void HexDump::mouseReleaseEvent(QMouseEvent* event)
{
bool wAccept = true;
if((event->buttons() & Qt::LeftButton) == 0)
{
if(mGuiState == HexDump::MultiRowsSelectionState)
{
mGuiState = HexDump::NoState;
repaint();
wAccept = false;
}
}
if(wAccept == true)
AbstractTableView::mouseReleaseEvent(event);
}
QString HexDump::paintContent(QPainter* painter, int_t rowBase, int rowOffset, int col, int x, int y, int w, int h)
{
// Reset byte offset when base address is reached
if(rowBase == 0 && mByteOffset != 0)
printDumpAt(mMemPage->getBase(), false);
// Compute RVA
int wBytePerRowCount = getBytePerRowCount();
int_t wRva = (rowBase + rowOffset) * wBytePerRowCount - mByteOffset;
QString wStr = "";
if(col == 0) // Addresses
{
wStr += QString("%1").arg(rvaToVa(wRva), sizeof(int_t) * 2, 16, QChar('0')).toUpper();
}
else if(mDescriptor.at(col - 1).isData == true) //paint data
{
printSelected(painter, rowBase, rowOffset, col, x, y, w, h);
QList<RichTextPainter::CustomRichText_t> richText;
getString(col - 1, wRva, &richText);
RichTextPainter::paintRichText(painter, x, y, w, h, 4, &richText, getCharWidth());
}
else //paint non-data
{
}
return wStr;
}
void HexDump::printSelected(QPainter* painter, int_t rowBase, int rowOffset, int col, int x, int y, int w, int h)
{
if((col > 0) && ((col - 1) < mDescriptor.size()))
{
int wI = 0;
int wBytePerRowCount = getBytePerRowCount();
int_t wRva = (rowBase + rowOffset) * wBytePerRowCount - mByteOffset;
int wItemPixWidth = getItemPixelWidth(mDescriptor.at(col - 1));
int wCharWidth = getCharWidth();
if(wItemPixWidth == wCharWidth)
x += 4;
int wSelectionX;
int wSelectionWidth;
for(wI = 0; wI < mDescriptor.at(col - 1).itemCount; wI++)
{
if(isSelected(wRva + wI * getSizeOf(mDescriptor.at(col - 1).data.itemSize)) == true)
{
wSelectionX = x + wI * wItemPixWidth;
wSelectionWidth = wItemPixWidth > w - (wSelectionX - x) ? w - (wSelectionX - x) : wItemPixWidth;
wSelectionWidth = wSelectionWidth < 0 ? 0 : wSelectionWidth;
painter->setPen(textColor);
painter->fillRect(QRect(wSelectionX, y, wSelectionWidth, h), QBrush(selectionColor));
}
}
}
}
/************************************************************************************
Selection Management
************************************************************************************/
void HexDump::expandSelectionUpTo(int_t rva)
{
if(rva < mSelection.firstSelectedIndex)
{
mSelection.fromIndex = rva;
mSelection.toIndex = mSelection.firstSelectedIndex;
}
else if(rva > mSelection.firstSelectedIndex)
{
mSelection.fromIndex = mSelection.firstSelectedIndex;
mSelection.toIndex = rva;
}
else if(rva == mSelection.firstSelectedIndex)
{
setSingleSelection(rva);
}
}
void HexDump::setSingleSelection(int_t rva)
{
mSelection.firstSelectedIndex = rva;
mSelection.fromIndex = rva;
mSelection.toIndex = rva;
}
int_t HexDump::getInitialSelection()
{
return mSelection.firstSelectedIndex;
}
int_t HexDump::getSelectionStart()
{
return mSelection.fromIndex;
}
int_t HexDump::getSelectionEnd()
{
return mSelection.toIndex;
}
bool HexDump::isSelected(int_t rva)
{
if(rva >= mSelection.fromIndex && rva <= mSelection.toIndex)
return true;
else
return false;
}
void HexDump::getString(int col, int_t rva, QList<RichTextPainter::CustomRichText_t>* richText)
{
int wI;
QString wStr = "";
int wByteCount = getSizeOf(mDescriptor.at(col).data.itemSize);
int wBufferByteCount = mDescriptor.at(col).itemCount * wByteCount;
wBufferByteCount = wBufferByteCount > (int_t)(mMemPage->getSize() - rva) ? mMemPage->getSize() - rva : wBufferByteCount;
byte_t* wData = new byte_t[wBufferByteCount];
//byte_t wData[mDescriptor.at(col).itemCount * wByteCount];
mMemPage->read(wData, rva, wBufferByteCount);
RichTextPainter::CustomRichText_t curData;
curData.highlight = false;
curData.flags = RichTextPainter::FlagColor;
QColor highlightColor = ConfigColor("HexDumpModifiedBytesColor");
for(wI = 0; wI < mDescriptor.at(col).itemCount && (rva + wI) < (int_t)mMemPage->getSize(); wI++)
{
int maxLen = getStringMaxLength(mDescriptor.at(col).data);
QString append = " ";
if(!maxLen)
append="";
if((rva + wI + wByteCount - 1) < (int_t)mMemPage->getSize())
wStr = toString(mDescriptor.at(col).data, (void*)(wData + wI * wByteCount)).rightJustified(maxLen, ' ') + append;
else
wStr = QString("?").rightJustified(maxLen, ' ') + append;
curData.text = wStr;
int_t start = rvaToVa(rva + wI * wByteCount);
int_t end = start + wByteCount - 1;
curData.textColor = DbgFunctions()->PatchInRange(start, end) ? highlightColor : textColor;
richText->push_back(curData);
}
delete[] wData;
}
QString HexDump::toString(DataDescriptor_t desc, void* data) //convert data to string
{
QString wStr = "";
switch(desc.itemSize)
{
case Byte:
{
wStr = byteToString(*((byte_t*)data), desc.byteMode);
}
break;
case Word:
{
wStr = wordToString(*((uint16*)data), desc.wordMode);
}
break;
case Dword:
{
wStr = dwordToString(*((uint32*)data), desc.dwordMode);
}
break;
case Qword:
{
wStr = qwordToString(*((uint64*)data), desc.qwordMode);
}
break;
case Tword:
{
//TODO: sizeof(long double)=12, not 10
wStr = twordToString(*((long double*)data), desc.twordMode);
}
break;
default:
{
}
break;
}
return wStr;
}
QString HexDump::byteToString(byte_t byte, ByteViewMode_e mode)
{
QString wStr = "";
switch(mode)
{
case HexByte:
{
wStr = QString("%1").arg((unsigned char)byte, 2, 16, QChar('0')).toUpper();
}
break;
case AsciiByte:
{
QChar wChar((char)byte);
if(wChar.isPrint() == true)
wStr = QString(wChar);
else
wStr = ".";
}
break;
case SignedDecByte:
{
wStr = QString::number((int)((char)byte));
}
break;
case UnsignedDecByte:
{
wStr = QString::number((unsigned int)byte);
}
break;
default:
{
}
break;
}
return wStr;
}
QString HexDump::wordToString(uint16 word, WordViewMode_e mode)
{
QString wStr = "";
switch(mode)
{
case HexWord:
{
wStr = QString("%1").arg((unsigned short)word, 4, 16, QChar('0')).toUpper();
}
break;
case UnicodeWord:
{
QChar wChar((char)word&0xFF);
if(wChar.isPrint() == true && (word>>8)==0)
wStr = QString(wChar);
else
wStr = ".";
}
break;
case SignedDecWord:
{
wStr = QString::number((int)((short)word));
}
break;
case UnsignedDecWord:
{
wStr = QString::number((unsigned int)word);
}
break;
default:
{
}
break;
}
return wStr;
}
QString HexDump::dwordToString(uint32 dword, DwordViewMode_e mode)
{
QString wStr = "";
switch(mode)
{
case HexDword:
{
wStr = QString("%1").arg((unsigned int)dword, 8, 16, QChar('0')).toUpper();
}
break;
case SignedDecDword:
{
wStr = QString::number((int)dword);
}
break;
case UnsignedDecDword:
{
wStr = QString::number((unsigned int)dword);
}
break;
case FloatDword:
{
float* wPtr = (float*)&dword;
wStr = QString::number((double)*wPtr);
}
break;
default:
{
}
break;
}
return wStr;
}
QString HexDump::qwordToString(uint64 qword, QwordViewMode_e mode)
{
QString wStr = "";
switch(mode)
{
case HexQword:
{
wStr = QString("%1").arg((unsigned long long)qword, 16, 16, QChar('0')).toUpper();
}
break;
case SignedDecQword:
{
wStr = QString::number((long long)qword);
}
break;
case UnsignedDecQword:
{
wStr = QString::number((unsigned long long)qword);
}
break;
case DoubleQword:
{
double* wPtr = (double*)&qword;
wStr = QString::number((double)*wPtr);
}
break;
default:
{
}
break;
}
return wStr;
}
QString HexDump::twordToString(long double tword, TwordViewMode_e mode)
{
QString wStr = "";
switch(mode)
{
case FloatTword:
{
std::stringstream wlongDoubleStr;
wlongDoubleStr << std::scientific << (long double)tword;
wStr = QString::fromStdString(wlongDoubleStr.str());
}
break;
default:
{
}
break;
}
return wStr;
}
int HexDump::getSizeOf(DataSize_e size)
{
int wSize = 0;
switch(size)
{
case Byte: // 1 Byte
{
wSize = 1;
}
break;
case Word: // 2 Bytes
{
wSize = 2;
}
break;
case Dword: // 4 Bytes
{
wSize = 4;
}
break;
case Qword: // 8 Bytes
{
wSize = 8;
}
break;
case Tword: // 10 Bytes
{
wSize = 10;
}
break;
default:
{
wSize = 0;
}
}
return wSize;
}
int HexDump::getStringMaxLength(DataDescriptor_t desc)
{
int wLength = 0;
switch(desc.itemSize)
{
case Byte:
{
wLength = byteStringMaxLength(desc.byteMode);
}
break;
case Word:
{
wLength = wordStringMaxLength(desc.wordMode);
}
break;
case Dword:
{
wLength = dwordStringMaxLength(desc.dwordMode);
}
break;
case Qword:
{
wLength = qwordStringMaxLength(desc.qwordMode);
}
break;
case Tword:
{
wLength = twordStringMaxLength(desc.twordMode);
}
break;
default:
{
}
break;
}
return wLength;
}
int HexDump::byteStringMaxLength(ByteViewMode_e mode)
{
int wLength = 0;
switch(mode)
{
case HexByte:
{
wLength = 2;
}
break;
case AsciiByte:
{
wLength = 0;
}
break;
case SignedDecByte:
{
wLength = 4;
}
break;
case UnsignedDecByte:
{
wLength = 3;
}
break;
default:
{
}
break;
}
return wLength;
}
int HexDump::wordStringMaxLength(WordViewMode_e mode)
{
int wLength = 0;
switch(mode)
{
case HexWord:
{
wLength = 4;
}
break;
case UnicodeWord:
{
wLength = 0;
}
break;
case SignedDecWord:
{
wLength = 6;
}
break;
case UnsignedDecWord:
{
wLength = 5;
}
break;
default:
{
}
break;
}
return wLength;
}
int HexDump::dwordStringMaxLength(DwordViewMode_e mode)
{
int wLength = 0;
switch(mode)
{
case HexDword:
{
wLength = 8;
}
break;
case SignedDecDword:
{
wLength = 11;
}
break;
case UnsignedDecDword:
{
wLength = 10;
}
break;
case FloatDword:
{
wLength = 13;
}
break;
default:
{
}
break;
}
return wLength;
}
int HexDump::qwordStringMaxLength(QwordViewMode_e mode)
{
int wLength = 0;
switch(mode)
{
case HexQword:
{
wLength = 16;
}
break;
case SignedDecQword:
{
wLength = 20;
}
break;
case UnsignedDecQword:
{
wLength = 20;
}
break;
case DoubleQword:
{
wLength = 23;
}
break;
default:
{
}
break;
}
return wLength;
}
int HexDump::twordStringMaxLength(TwordViewMode_e mode)
{
int wLength = 0;
switch(mode)
{
case FloatTword:
{
wLength = 29;
}
break;
default:
{
}
break;
}
return wLength;
}
int HexDump::getItemIndexFromX(int x)
{
int wColIndex = getColumnIndexFromX(x);
if(wColIndex > 0)
{
int wColStartingPos = getColumnPosition(wColIndex);
int wRelativeX = x - wColStartingPos;
int wItemPixWidth = getItemPixelWidth(mDescriptor.at(wColIndex - 1));
int wCharWidth = getCharWidth();
if(wItemPixWidth == wCharWidth)
wRelativeX -= 4;
int wItemIndex = wRelativeX / wItemPixWidth;
wItemIndex = wItemIndex < 0 ? 0 : wItemIndex;
wItemIndex = wItemIndex > (mDescriptor.at(wColIndex - 1).itemCount - 1) ? (mDescriptor.at(wColIndex - 1).itemCount - 1) : wItemIndex;
return wItemIndex;
}
else
{
return 0;
}
}
int_t HexDump::getItemStartingAddress(int x, int y)
{
int wRowOffset = getIndexOffsetFromY(transY(y));
int wItemIndex = getItemIndexFromX(x);
int wColIndex = getColumnIndexFromX(x);
int_t wStartingAddress = 0;
if(wColIndex > 0)
{
wColIndex -= 1;
wStartingAddress = (getTableOffset() + wRowOffset) * (mDescriptor.at(wColIndex).itemCount * getSizeOf(mDescriptor.at(wColIndex).data.itemSize)) + wItemIndex * getSizeOf(mDescriptor.at(wColIndex).data.itemSize) - mByteOffset;
}
return wStartingAddress;
}
int HexDump::getBytePerRowCount()
{
return mDescriptor.at(0).itemCount * getSizeOf(mDescriptor.at(0).data.itemSize);
}
int HexDump::getItemPixelWidth(ColumnDescriptor_t desc)
{
int wCharWidth = getCharWidth();
int wItemPixWidth = getStringMaxLength(desc.data) * wCharWidth + wCharWidth;
return wItemPixWidth;
}
void HexDump::appendDescriptor(int width, QString title, bool clickable, ColumnDescriptor_t descriptor)
{
addColumnAt(width, title, clickable);
mDescriptor.append(descriptor);
}
//Clears the descriptors, append a new descriptor and fix the tableOffset (use this instead of clearDescriptors()
void HexDump::appendResetDescriptor(int width, QString title, bool clickable, ColumnDescriptor_t descriptor)
{
if(mDescriptor.size())
{
int_t wRVA = getTableOffset() * getBytePerRowCount() - mByteOffset;
clearDescriptors();
appendDescriptor(width, title, clickable, descriptor);
printDumpAt(rvaToVa(wRVA));
}
else
appendDescriptor(width, title, clickable, descriptor);
}
void HexDump::clearDescriptors()
{
deleteAllColumns();
mDescriptor.clear();
int charwidth=getCharWidth();
addColumnAt(8+charwidth*2*sizeof(uint_t), "Address", false); //address
}
void HexDump::debugStateChanged(DBGSTATE state)
{
if(state==stopped)
{
mMemPage->setAttributes(0, 0);
setRowCount(0);
reloadData();
}
}