1486 lines
50 KiB
C++
1486 lines
50 KiB
C++
#include "Disassembly.h"
|
|
#include "Configuration.h"
|
|
#include "Bridge.h"
|
|
|
|
Disassembly::Disassembly(QWidget* parent) : AbstractTableView(parent)
|
|
{
|
|
fontsUpdated();
|
|
mMemPage = new MemoryPage(0, 0);
|
|
|
|
mInstBuffer.clear();
|
|
|
|
historyClear();
|
|
|
|
SelectionData_t data;
|
|
memset(&data, 0, sizeof(SelectionData_t));
|
|
mSelection = data;
|
|
|
|
mCipRva = 0;
|
|
mIsRunning = false;
|
|
|
|
mHighlightToken.text = "";
|
|
mHighlightingMode = false;
|
|
|
|
mDisasm = new QBeaEngine();
|
|
|
|
mIsLastInstDisplayed = false;
|
|
|
|
mGuiState = Disassembly::NoState;
|
|
|
|
setRowCount(mMemPage->getSize());
|
|
|
|
addColumnAt(getCharWidth() * 2 * sizeof(int_t) + 8, "", false); //address
|
|
addColumnAt(getCharWidth() * 2 * 12 + 8, "", false); //bytes
|
|
addColumnAt(getCharWidth() * 40, "", false); //disassembly
|
|
addColumnAt(1000, "", false); //comments
|
|
|
|
setShowHeader(false); //hide header
|
|
|
|
backgroundColor = ConfigColor("DisassemblyBackgroundColor");
|
|
|
|
connect(Bridge::getBridge(), SIGNAL(repaintGui()), this, SLOT(reloadData()));
|
|
}
|
|
|
|
void Disassembly::colorsUpdated()
|
|
{
|
|
AbstractTableView::colorsUpdated();
|
|
backgroundColor = ConfigColor("DisassemblyBackgroundColor");
|
|
}
|
|
|
|
void Disassembly::fontsUpdated()
|
|
{
|
|
setFont(ConfigFont("Disassembly"));
|
|
}
|
|
|
|
/************************************************************************************
|
|
Reimplemented Functions
|
|
************************************************************************************/
|
|
/**
|
|
* @brief This method has been reimplemented. It returns the string to paint or paints it
|
|
* by its own.
|
|
*
|
|
* @param[in] painter Pointer to the painter that allows painting by its own
|
|
* @param[in] rowBase Index of the top item (Table offset)
|
|
* @param[in] rowOffset Index offset starting from rowBase
|
|
* @param[in] col Column index
|
|
* @param[in] x Rectangle x
|
|
* @param[in] y Rectangle y
|
|
* @param[in] w Rectangle width
|
|
* @param[in] h Rectangle heigth
|
|
*
|
|
* @return String to paint.
|
|
*/
|
|
QString Disassembly::paintContent(QPainter* painter, int_t rowBase, int rowOffset, int col, int x, int y, int w, int h)
|
|
{
|
|
Q_UNUSED(rowBase)
|
|
if(mHighlightingMode)
|
|
{
|
|
QPen pen(ConfigColor("InstructionHighlightColor"));
|
|
pen.setWidth(2);
|
|
painter->setPen(pen);
|
|
QRect rect = viewport()->rect();
|
|
rect.adjust(1, 1, -1, -1);
|
|
painter->drawRect(rect);
|
|
}
|
|
int_t wRVA = mInstBuffer.at(rowOffset).rva;
|
|
bool wIsSelected = isSelected(&mInstBuffer, rowOffset);
|
|
|
|
// Highlight if selected
|
|
if(wIsSelected)
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("DisassemblySelectionColor")));
|
|
|
|
switch(col)
|
|
{
|
|
case 0: // Draw address (+ label)
|
|
{
|
|
char label[MAX_LABEL_SIZE] = "";
|
|
int_t cur_addr = rvaToVa(mInstBuffer.at(rowOffset).rva);
|
|
QString addrText = getAddrText(cur_addr, label);
|
|
BPXTYPE bpxtype = DbgGetBpxTypeAt(cur_addr);
|
|
bool isbookmark = DbgGetBookmarkAt(cur_addr);
|
|
if(mInstBuffer.at(rowOffset).rva == mCipRva && !mIsRunning) //cip + not running
|
|
{
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("DisassemblyCipBackgroundColor")));
|
|
if(!isbookmark) //no bookmark
|
|
{
|
|
if(bpxtype & bp_normal) //normal breakpoint
|
|
{
|
|
QColor bpColor = ConfigColor("DisassemblyBreakpointBackgroundColor");
|
|
if(!bpColor.alpha()) //we don't want transparent text
|
|
bpColor = ConfigColor("DisassemblyBreakpointColor");
|
|
if(bpColor == ConfigColor("DisassemblyCipBackgroundColor"))
|
|
bpColor = ConfigColor("DisassemblyCipColor");
|
|
painter->setPen(QPen(bpColor));
|
|
}
|
|
else if(bpxtype & bp_hardware) //hardware breakpoint only
|
|
{
|
|
QColor hwbpColor = ConfigColor("DisassemblyHardwareBreakpointBackgroundColor");
|
|
if(!hwbpColor.alpha()) //we don't want transparent text
|
|
hwbpColor = ConfigColor("DisassemblyHardwareBreakpointColor");
|
|
if(hwbpColor == ConfigColor("DisassemblyCipBackgroundColor"))
|
|
hwbpColor = ConfigColor("DisassemblyCipColor");
|
|
painter->setPen(hwbpColor);
|
|
}
|
|
else //no breakpoint
|
|
{
|
|
painter->setPen(QPen(ConfigColor("DisassemblyCipColor")));
|
|
}
|
|
}
|
|
else //bookmark
|
|
{
|
|
QColor bookmarkColor = ConfigColor("DisassemblyBookmarkBackgroundColor");
|
|
if(!bookmarkColor.alpha()) //we don't want transparent text
|
|
bookmarkColor = ConfigColor("DisassemblyBookmarkColor");
|
|
if(bookmarkColor == ConfigColor("DisassemblyCipBackgroundColor"))
|
|
bookmarkColor = ConfigColor("DisassemblyCipColor");
|
|
painter->setPen(QPen(bookmarkColor));
|
|
}
|
|
}
|
|
else //non-cip address
|
|
{
|
|
if(!isbookmark) //no bookmark
|
|
{
|
|
if(*label) //label
|
|
{
|
|
if(bpxtype == bp_none) //label only
|
|
{
|
|
painter->setPen(QPen(ConfigColor("DisassemblyLabelColor"))); //red -> address + label text
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("DisassemblyLabelBackgroundColor"))); //fill label background
|
|
}
|
|
else //label+breakpoint
|
|
{
|
|
if(bpxtype & bp_normal) //label + normal breakpoint
|
|
{
|
|
painter->setPen(QPen(ConfigColor("DisassemblyBreakpointColor")));
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("DisassemblyBreakpointBackgroundColor"))); //fill red
|
|
}
|
|
else if(bpxtype & bp_hardware) //label + hardware breakpoint only
|
|
{
|
|
painter->setPen(QPen(ConfigColor("DisassemblyHardwareBreakpointColor")));
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("DisassemblyHardwareBreakpointBackgroundColor"))); //fill ?
|
|
}
|
|
else //other cases -> do as normal
|
|
{
|
|
painter->setPen(QPen(ConfigColor("DisassemblyLabelColor"))); //red -> address + label text
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("DisassemblyLabelBackgroundColor"))); //fill label background
|
|
}
|
|
}
|
|
}
|
|
else //no label
|
|
{
|
|
if(bpxtype == bp_none) //no label, no breakpoint
|
|
{
|
|
QColor background;
|
|
if(wIsSelected)
|
|
{
|
|
background = ConfigColor("DisassemblySelectedAddressBackgroundColor");
|
|
painter->setPen(QPen(ConfigColor("DisassemblySelectedAddressColor"))); //black address (DisassemblySelectedAddressColor)
|
|
}
|
|
else
|
|
{
|
|
background = ConfigColor("DisassemblyAddressBackgroundColor");
|
|
painter->setPen(QPen(ConfigColor("DisassemblyAddressColor"))); //DisassemblyAddressColor
|
|
}
|
|
if(background.alpha())
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(background)); //fill background
|
|
}
|
|
else //breakpoint only
|
|
{
|
|
if(bpxtype & bp_normal) //normal breakpoint
|
|
{
|
|
painter->setPen(QPen(ConfigColor("DisassemblyBreakpointColor")));
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("DisassemblyBreakpointBackgroundColor"))); //fill red
|
|
}
|
|
else if(bpxtype & bp_hardware) //hardware breakpoint only
|
|
{
|
|
painter->setPen(QPen(ConfigColor("DisassemblyHardwareBreakpointColor")));
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("DisassemblyHardwareBreakpointBackgroundColor"))); //fill red
|
|
}
|
|
else //other cases (memory breakpoint in disassembly) -> do as normal
|
|
{
|
|
QColor background;
|
|
if(wIsSelected)
|
|
{
|
|
background = ConfigColor("DisassemblySelectedAddressBackgroundColor");
|
|
painter->setPen(QPen(ConfigColor("DisassemblySelectedAddressColor"))); //black address (DisassemblySelectedAddressColor)
|
|
}
|
|
else
|
|
{
|
|
background = ConfigColor("DisassemblyAddressBackgroundColor");
|
|
painter->setPen(QPen(ConfigColor("DisassemblyAddressColor")));
|
|
}
|
|
if(background.alpha())
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(background)); //fill background
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else //bookmark
|
|
{
|
|
if(*label) //label + bookmark
|
|
{
|
|
if(bpxtype == bp_none) //label + bookmark
|
|
{
|
|
painter->setPen(QPen(ConfigColor("DisassemblyLabelColor"))); //red -> address + label text
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("DisassemblyBookmarkBackgroundColor"))); //fill label background
|
|
}
|
|
else //label+breakpoint+bookmark
|
|
{
|
|
QColor color = ConfigColor("DisassemblyBookmarkBackgroundColor");
|
|
if(!color.alpha()) //we don't want transparent text
|
|
color = ConfigColor("DisassemblyAddressColor");
|
|
painter->setPen(QPen(color));
|
|
if(bpxtype & bp_normal) //label + bookmark + normal breakpoint
|
|
{
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("DisassemblyBreakpointBackgroundColor"))); //fill red
|
|
}
|
|
else if(bpxtype & bp_hardware) //label + bookmark + hardware breakpoint only
|
|
{
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("DisassemblyHardwareBreakpointBackgroundColor"))); //fill ?
|
|
}
|
|
}
|
|
}
|
|
else //bookmark, no label
|
|
{
|
|
if(bpxtype == bp_none) //bookmark only
|
|
{
|
|
painter->setPen(QPen(ConfigColor("DisassemblyBookmarkColor"))); //black address
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("DisassemblyBookmarkBackgroundColor"))); //fill bookmark color
|
|
}
|
|
else //bookmark + breakpoint
|
|
{
|
|
QColor color = ConfigColor("DisassemblyBookmarkBackgroundColor");
|
|
if(!color.alpha()) //we don't want transparent text
|
|
color = ConfigColor("DisassemblyAddressColor");
|
|
painter->setPen(QPen(color));
|
|
if(bpxtype & bp_normal) //bookmark + normal breakpoint
|
|
{
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("DisassemblyBreakpointBackgroundColor"))); //fill red
|
|
}
|
|
else if(bpxtype & bp_hardware) //bookmark + hardware breakpoint only
|
|
{
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("DisassemblyHardwareBreakpointBackgroundColor"))); //fill red
|
|
}
|
|
else //other cases (bookmark + memory breakpoint in disassembly) -> do as normal
|
|
{
|
|
painter->setPen(QPen(ConfigColor("DisassemblyBookmarkColor"))); //black address (DisassemblySelectedAddressColor)
|
|
painter->fillRect(QRect(x, y, w, h), QBrush(ConfigColor("DisassemblyBookmarkBackgroundColor"))); //fill bookmark color
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
painter->drawText(QRect(x + 4, y , w - 4 , h), Qt::AlignVCenter | Qt::AlignLeft, addrText);
|
|
}
|
|
break;
|
|
|
|
case 1: //draw bytes (TODO: some spaces between bytes)
|
|
{
|
|
//draw functions
|
|
int_t cur_addr = rvaToVa(mInstBuffer.at(rowOffset).rva);
|
|
Function_t funcType;
|
|
FUNCTYPE funcFirst = DbgGetFunctionTypeAt(cur_addr);
|
|
FUNCTYPE funcLast = DbgGetFunctionTypeAt(cur_addr + mInstBuffer.at(rowOffset).length - 1);
|
|
if(funcLast == FUNC_END)
|
|
funcFirst = funcLast;
|
|
switch(funcFirst)
|
|
{
|
|
case FUNC_SINGLE:
|
|
funcType = Function_single;
|
|
break;
|
|
case FUNC_NONE:
|
|
funcType = Function_none;
|
|
break;
|
|
case FUNC_BEGIN:
|
|
funcType = Function_start;
|
|
break;
|
|
case FUNC_MIDDLE:
|
|
funcType = Function_middle;
|
|
break;
|
|
case FUNC_END:
|
|
funcType = Function_end;
|
|
break;
|
|
}
|
|
int funcsize = paintFunctionGraphic(painter, x, y, funcType, false);
|
|
|
|
//draw jump arrows
|
|
int jumpsize = paintJumpsGraphic(painter, x + funcsize, y, wRVA); //jump line
|
|
|
|
//draw bytes
|
|
QColor bytesColor = ConfigColor("DisassemblyBytesColor");
|
|
QColor patchedBytesColor = ConfigColor("DisassemblyModifiedBytesColor");
|
|
QList<RichTextPainter::CustomRichText_t> richBytes;
|
|
RichTextPainter::CustomRichText_t space;
|
|
space.highlight = false;
|
|
space.flags = RichTextPainter::FlagNone;
|
|
space.text = " ";
|
|
RichTextPainter::CustomRichText_t curByte;
|
|
curByte.highlight = false;
|
|
curByte.flags = RichTextPainter::FlagColor;
|
|
for(int i = 0; i < mInstBuffer.at(rowOffset).dump.size(); i++)
|
|
{
|
|
if(i)
|
|
richBytes.push_back(space);
|
|
curByte.text = QString("%1").arg((unsigned char)(mInstBuffer.at(rowOffset).dump.at(i)), 2, 16, QChar('0')).toUpper();
|
|
curByte.textColor = DbgFunctions()->PatchGet(cur_addr + i) ? patchedBytesColor : bytesColor;
|
|
richBytes.push_back(curByte);
|
|
}
|
|
RichTextPainter::paintRichText(painter, x, y, getColumnWidth(col), getRowHeight(), jumpsize + funcsize, &richBytes, getCharWidth());
|
|
}
|
|
break;
|
|
|
|
case 2: //draw disassembly (with colours needed)
|
|
{
|
|
int_t cur_addr = rvaToVa(mInstBuffer.at(rowOffset).rva);
|
|
int loopsize = 0;
|
|
int depth = 0;
|
|
|
|
while(1) //paint all loop depths
|
|
{
|
|
LOOPTYPE loopType = DbgGetLoopTypeAt(cur_addr, depth);
|
|
if(loopType == LOOP_NONE)
|
|
break;
|
|
Function_t funcType;
|
|
switch(loopType)
|
|
{
|
|
case LOOP_BEGIN:
|
|
funcType = Function_start;
|
|
break;
|
|
case LOOP_ENTRY:
|
|
funcType = Function_loop_entry;
|
|
break;
|
|
case LOOP_MIDDLE:
|
|
funcType = Function_middle;
|
|
break;
|
|
case LOOP_END:
|
|
funcType = Function_end;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
loopsize += paintFunctionGraphic(painter, x + loopsize, y, funcType, true);
|
|
depth++;
|
|
}
|
|
|
|
QList<RichTextPainter::CustomRichText_t> richText;
|
|
|
|
BeaTokenizer::BeaInstructionToken* token = &mInstBuffer[rowOffset].tokens;
|
|
if(mHighlightToken.text.length())
|
|
BeaTokenizer::TokenToRichText(token, &richText, &mHighlightToken);
|
|
else
|
|
BeaTokenizer::TokenToRichText(token, &richText, 0);
|
|
int xinc = 4;
|
|
RichTextPainter::paintRichText(painter, x + loopsize, y, getColumnWidth(col) - loopsize, getRowHeight(), xinc, &richText, getCharWidth());
|
|
token->x = x + loopsize + xinc;
|
|
}
|
|
break;
|
|
|
|
case 3: //draw comments
|
|
{
|
|
char comment[MAX_COMMENT_SIZE] = "";
|
|
if(DbgGetCommentAt(rvaToVa(mInstBuffer.at(rowOffset).rva), comment))
|
|
{
|
|
painter->setPen(ConfigColor("DisassemblyCommentColor"));
|
|
int width = getCharWidth() * QString(comment).length() + 4;
|
|
if(width > w)
|
|
width = w;
|
|
if(width)
|
|
painter->fillRect(QRect(x + 2, y, width, h), QBrush(ConfigColor("DisassemblyCommentBackgroundColor"))); //fill bookmark color
|
|
painter->drawText(QRect(x + 4, y , w - 4 , h), Qt::AlignVCenter | Qt::AlignLeft, QString(comment));
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
return "";
|
|
}
|
|
|
|
|
|
/************************************************************************************
|
|
Mouse Management
|
|
************************************************************************************/
|
|
/**
|
|
* @brief This method has been reimplemented. It manages the following actions:
|
|
* - Multi-rows selection
|
|
*
|
|
* @param[in] event Mouse event
|
|
*
|
|
* @return Nothing.
|
|
*/
|
|
void Disassembly::mouseMoveEvent(QMouseEvent* event)
|
|
{
|
|
//qDebug() << "Disassembly::mouseMoveEvent";
|
|
|
|
bool wAccept = true;
|
|
|
|
if(mGuiState == Disassembly::MultiRowsSelectionState)
|
|
{
|
|
//qDebug() << "State = MultiRowsSelectionState";
|
|
|
|
if((transY(event->y()) >= 0) && (transY(event->y()) <= this->getTableHeigth()))
|
|
{
|
|
int wI = getIndexOffsetFromY(transY(event->y()));
|
|
|
|
if(mMemPage->getSize() > 0)
|
|
{
|
|
// Bound
|
|
wI = wI >= mInstBuffer.size() ? mInstBuffer.size() - 1 : wI;
|
|
wI = wI < 0 ? 0 : wI;
|
|
|
|
int_t wRowIndex = mInstBuffer.at(wI).rva;
|
|
int_t wInstrSize = getInstructionRVA(wRowIndex, 1) - wRowIndex - 1;
|
|
|
|
if(wRowIndex < getRowCount())
|
|
{
|
|
setSingleSelection(getInitialSelection());
|
|
expandSelectionUpTo(getInstructionRVA(getInitialSelection(), 1) - 1);
|
|
if(wRowIndex > getInitialSelection()) //select down
|
|
expandSelectionUpTo(wRowIndex + wInstrSize);
|
|
else
|
|
expandSelectionUpTo(wRowIndex);
|
|
|
|
repaint();
|
|
|
|
wAccept = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(wAccept == true)
|
|
AbstractTableView::mouseMoveEvent(event);
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief This method has been reimplemented. It manages the following actions:
|
|
* - Multi-rows selection
|
|
*
|
|
* @param[in] event Mouse event
|
|
*
|
|
* @return Nothing.
|
|
*/
|
|
void Disassembly::mousePressEvent(QMouseEvent* event)
|
|
{
|
|
bool wAccept = false;
|
|
|
|
if(DbgIsDebugging() && ((event->buttons() & Qt::LeftButton) != 0) && ((event->buttons() & Qt::RightButton) == 0))
|
|
{
|
|
if(getGuiState() == AbstractTableView::NoState)
|
|
{
|
|
if(mHighlightingMode)
|
|
{
|
|
if(getColumnIndexFromX(event->x()) == 2) //click in instruction column
|
|
{
|
|
int rowOffset = getIndexOffsetFromY(transY(event->y()));
|
|
if(rowOffset < mInstBuffer.size())
|
|
{
|
|
BeaTokenizer::BeaSingleToken token;
|
|
if(BeaTokenizer::TokenFromX(&mInstBuffer.at(rowOffset).tokens, &token, event->x(), getCharWidth()))
|
|
{
|
|
if(BeaTokenizer::IsHighlightableToken(&token) && !BeaTokenizer::TokenEquals(&token, &mHighlightToken))
|
|
mHighlightToken = token;
|
|
else
|
|
{
|
|
mHighlightToken.value.value = 0;
|
|
mHighlightToken.text = "";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mHighlightToken.value.value = 0;
|
|
mHighlightToken.text = "";
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
mHighlightToken.value.value = 0;
|
|
mHighlightToken.text = "";
|
|
}
|
|
}
|
|
else if(event->y() > getHeaderHeight())
|
|
{
|
|
int_t wRowIndex = getInstructionRVA(getTableOffset(), getIndexOffsetFromY(transY(event->y())));
|
|
int_t wInstrSize = getInstructionRVA(wRowIndex, 1) - wRowIndex - 1;
|
|
|
|
if(wRowIndex < getRowCount())
|
|
{
|
|
if(!(event->modifiers() & Qt::ShiftModifier)) //SHIFT pressed
|
|
setSingleSelection(wRowIndex);
|
|
if(getSelectionStart() > wRowIndex) //select up
|
|
{
|
|
setSingleSelection(getInitialSelection());
|
|
expandSelectionUpTo(getInstructionRVA(getInitialSelection(), 1) - 1);
|
|
expandSelectionUpTo(wRowIndex);
|
|
}
|
|
else //select down
|
|
{
|
|
setSingleSelection(getInitialSelection());
|
|
expandSelectionUpTo(wRowIndex + wInstrSize);
|
|
}
|
|
|
|
mGuiState = Disassembly::MultiRowsSelectionState;
|
|
|
|
repaint();
|
|
|
|
wAccept = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(wAccept == false)
|
|
AbstractTableView::mousePressEvent(event);
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief This method has been reimplemented. It manages the following actions:
|
|
* - Multi-rows selection
|
|
*
|
|
* @param[in] event Mouse event
|
|
*
|
|
* @return Nothing.
|
|
*/
|
|
void Disassembly::mouseReleaseEvent(QMouseEvent* event)
|
|
{
|
|
bool wAccept = true;
|
|
|
|
if((event->buttons() & Qt::LeftButton) == 0)
|
|
{
|
|
if(mGuiState == Disassembly::MultiRowsSelectionState)
|
|
{
|
|
mGuiState = Disassembly::NoState;
|
|
|
|
repaint();
|
|
|
|
wAccept = false;
|
|
}
|
|
}
|
|
|
|
if(wAccept == true)
|
|
AbstractTableView::mouseReleaseEvent(event);
|
|
}
|
|
|
|
|
|
/************************************************************************************
|
|
Keyboard Management
|
|
************************************************************************************/
|
|
/**
|
|
* @brief This method has been reimplemented. It processes the Up/Down key events.
|
|
*
|
|
* @param[in] event Key event
|
|
*
|
|
* @return Nothing.
|
|
*/
|
|
void Disassembly::keyPressEvent(QKeyEvent* event)
|
|
{
|
|
int key = event->key();
|
|
|
|
if(key == Qt::Key_Up || key == Qt::Key_Down)
|
|
{
|
|
int_t botRVA = getTableOffset();
|
|
int_t topRVA = getInstructionRVA(getTableOffset(), getNbrOfLineToPrint() - 1);
|
|
|
|
bool expand = false;
|
|
if(event->modifiers() & Qt::ShiftModifier) //SHIFT pressed
|
|
expand = true;
|
|
|
|
if(key == Qt::Key_Up)
|
|
selectPrevious(expand);
|
|
else
|
|
selectNext(expand);
|
|
|
|
if(getSelectionStart() < botRVA)
|
|
{
|
|
setTableOffset(getSelectionStart());
|
|
}
|
|
else if(getSelectionEnd() >= topRVA)
|
|
{
|
|
setTableOffset(getInstructionRVA(getSelectionEnd(), -getNbrOfLineToPrint() + 2));
|
|
}
|
|
|
|
repaint();
|
|
}
|
|
else if(key == Qt::Key_Return || key == Qt::Key_Enter)
|
|
{
|
|
uint_t dest = DbgGetBranchDestination(rvaToVa(getInitialSelection()));
|
|
if(!dest)
|
|
return;
|
|
QString cmd = "disasm " + QString("%1").arg(dest, sizeof(int_t) * 2, 16, QChar('0')).toUpper();
|
|
DbgCmdExec(cmd.toUtf8().constData());
|
|
}
|
|
else
|
|
AbstractTableView::keyPressEvent(event);
|
|
}
|
|
|
|
/************************************************************************************
|
|
ScrollBar Management
|
|
***********************************************************************************/
|
|
/**
|
|
* @brief This method has been reimplemented. It realigns the slider on real instructions except
|
|
* when the type is QAbstractSlider::SliderNoAction. This type (QAbstractSlider::SliderNoAction)
|
|
* is used to force the disassembling at a specific RVA.
|
|
*
|
|
* @param[in] type Type of action
|
|
* @param[in] value Old table offset
|
|
* @param[in] delta Scrollbar value delta compared to the previous state
|
|
*
|
|
* @return Return the value of the new table offset.
|
|
*/
|
|
int_t Disassembly::sliderMovedHook(int type, int_t value, int_t delta)
|
|
{
|
|
int_t wNewValue;
|
|
|
|
if(type == QAbstractSlider::SliderNoAction) // QAbstractSlider::SliderNoAction is used to disassembe at a specific address
|
|
{
|
|
wNewValue = value + delta;
|
|
}
|
|
else if(type == QAbstractSlider::SliderMove) // If it's a slider action, disassemble one instruction back and one instruction next in order to be aligned on a real instruction
|
|
{
|
|
if(value + delta > 0)
|
|
{
|
|
wNewValue = getInstructionRVA(value + delta, -1);
|
|
wNewValue = getInstructionRVA(wNewValue, 1);
|
|
}
|
|
else
|
|
wNewValue = 0;
|
|
}
|
|
else // For other actions, disassemble according to the delta
|
|
{
|
|
wNewValue = getInstructionRVA(value, delta);
|
|
}
|
|
|
|
return wNewValue;
|
|
}
|
|
|
|
|
|
/************************************************************************************
|
|
Jumps Graphic
|
|
************************************************************************************/
|
|
/**
|
|
* @brief This method paints the graphic for jumps.
|
|
*
|
|
* @param[in] painter Pointer to the painter that allows painting by its own
|
|
* @param[in] x Rectangle x
|
|
* @param[in] y Rectangle y
|
|
* @param[in] addr RVA of address to process
|
|
*
|
|
* @return Nothing.
|
|
*/
|
|
int Disassembly::paintJumpsGraphic(QPainter* painter, int x, int y, int_t addr)
|
|
{
|
|
int_t selHeadRVA = mSelection.fromIndex;
|
|
int_t rva = addr;
|
|
Instruction_t instruction = DisassembleAt(selHeadRVA);
|
|
Int32 branchType = instruction.disasm.Instruction.BranchType;
|
|
|
|
GraphicDump_t wPict = GD_Nothing;
|
|
|
|
if(branchType && branchType != RetType && branchType != CallType)
|
|
{
|
|
int_t destRVA = (int_t)DbgGetBranchDestination(rvaToVa(instruction.rva));
|
|
|
|
int_t base = mMemPage->getBase();
|
|
if(destRVA >= base && destRVA < base + (int_t)mMemPage->getSize())
|
|
{
|
|
destRVA -= (int_t)mMemPage->getBase();
|
|
|
|
if(destRVA < selHeadRVA)
|
|
{
|
|
if(rva == destRVA)
|
|
wPict = GD_HeadFromBottom;
|
|
else if(rva > destRVA && rva < selHeadRVA)
|
|
wPict = GD_Vert;
|
|
else if(rva == selHeadRVA)
|
|
wPict = GD_FootToTop;
|
|
}
|
|
else if(destRVA > selHeadRVA)
|
|
{
|
|
if(rva == selHeadRVA)
|
|
wPict = GD_FootToBottom;
|
|
else if(rva > selHeadRVA && rva < destRVA)
|
|
wPict = GD_Vert;
|
|
else if(rva == destRVA)
|
|
wPict = GD_HeadFromTop;
|
|
}
|
|
}
|
|
}
|
|
|
|
bool bIsExecute = DbgIsJumpGoingToExecute(rvaToVa(instruction.rva));
|
|
|
|
if(branchType == JmpType) //unconditional
|
|
{
|
|
painter->setPen(ConfigColor("DisassemblyUnconditionalJumpLineColor"));
|
|
}
|
|
else
|
|
{
|
|
if(bIsExecute)
|
|
painter->setPen(ConfigColor("DisassemblyConditionalJumpLineTrueColor"));
|
|
else
|
|
painter->setPen(ConfigColor("DisassemblyConditionalJumpLineFalseColor"));
|
|
}
|
|
|
|
if(wPict == GD_Vert)
|
|
{
|
|
painter->drawLine(x, y, x, y + getRowHeight());
|
|
}
|
|
else if(wPict == GD_FootToBottom)
|
|
{
|
|
painter->drawLine(x, y + getRowHeight() / 2, x + 5, y + getRowHeight() / 2);
|
|
painter->drawLine(x, y + getRowHeight() / 2, x, y + getRowHeight());
|
|
}
|
|
else if(wPict == GD_FootToTop)
|
|
{
|
|
painter->drawLine(x, y + getRowHeight() / 2, x + 5, y + getRowHeight() / 2);
|
|
painter->drawLine(x, y, x, y + getRowHeight() / 2);
|
|
}
|
|
else if(wPict == GD_HeadFromBottom)
|
|
{
|
|
QPoint wPoints[] =
|
|
{
|
|
QPoint(x + 3, y + getRowHeight() / 2 - 2),
|
|
QPoint(x + 5, y + getRowHeight() / 2),
|
|
QPoint(x + 3, y + getRowHeight() / 2 + 2),
|
|
};
|
|
|
|
painter->drawLine(x, y + getRowHeight() / 2, x + 5, y + getRowHeight() / 2);
|
|
painter->drawLine(x, y + getRowHeight() / 2, x, y + getRowHeight());
|
|
painter->drawPolyline(wPoints, 3);
|
|
}
|
|
else if(wPict == GD_HeadFromTop)
|
|
{
|
|
QPoint wPoints[] =
|
|
{
|
|
QPoint(x + 3, y + getRowHeight() / 2 - 2),
|
|
QPoint(x + 5, y + getRowHeight() / 2),
|
|
QPoint(x + 3, y + getRowHeight() / 2 + 2),
|
|
};
|
|
|
|
painter->drawLine(x, y + getRowHeight() / 2, x + 5, y + getRowHeight() / 2);
|
|
painter->drawLine(x, y, x, y + getRowHeight() / 2);
|
|
painter->drawPolyline(wPoints, 3);
|
|
}
|
|
|
|
return 7;
|
|
}
|
|
|
|
/************************************************************************************
|
|
Function Graphic
|
|
************************************************************************************/
|
|
/**
|
|
* @brief This method paints the graphic for functions/loops.
|
|
*
|
|
* @param[in] painter Pointer to the painter that allows painting by its own
|
|
* @param[in] x Rectangle x
|
|
* @param[in] y Rectangle y
|
|
* @param[in] funcType Type of drawing to make
|
|
*
|
|
* @return Width of the painted data.
|
|
*/
|
|
|
|
int Disassembly::paintFunctionGraphic(QPainter* painter, int x, int y, Function_t funcType, bool loop)
|
|
{
|
|
if(loop && funcType == Function_none)
|
|
return 0;
|
|
painter->setPen(QPen(Qt::black, 2)); //thick black line
|
|
int height = getRowHeight();
|
|
int x_add = 5;
|
|
int y_add = 4;
|
|
int end_add = 2;
|
|
int line_width = 3;
|
|
if(loop)
|
|
{
|
|
end_add = -1;
|
|
x_add = 4;
|
|
}
|
|
switch(funcType)
|
|
{
|
|
case Function_single:
|
|
{
|
|
if(loop)
|
|
y_add = height / 2 + 1;
|
|
painter->drawLine(x + x_add + line_width, y + y_add, x + x_add, y + y_add);
|
|
painter->drawLine(x + x_add, y + y_add, x + x_add, y + height - y_add - 1);
|
|
if(loop)
|
|
y_add = height / 2 - 1;
|
|
painter->drawLine(x + x_add, y + height - y_add, x + x_add + line_width, y + height - y_add);
|
|
}
|
|
break;
|
|
|
|
case Function_start:
|
|
{
|
|
if(loop)
|
|
y_add = height / 2 + 1;
|
|
painter->drawLine(x + x_add + line_width, y + y_add, x + x_add, y + y_add);
|
|
painter->drawLine(x + x_add, y + y_add, x + x_add, y + height);
|
|
}
|
|
break;
|
|
|
|
case Function_middle:
|
|
{
|
|
painter->drawLine(x + x_add, y, x + x_add, y + height);
|
|
}
|
|
break;
|
|
|
|
case Function_loop_entry:
|
|
{
|
|
int trisize = 2;
|
|
int y_start = (height - trisize * 2) / 2 + y;
|
|
painter->drawLine(x + x_add, y_start, x + trisize + x_add, y_start + trisize);
|
|
painter->drawLine(x + trisize + x_add, y_start + trisize, x + x_add, y_start + trisize * 2);
|
|
|
|
painter->drawLine(x + x_add, y, x + x_add, y_start - 1);
|
|
painter->drawLine(x + x_add, y_start + trisize * 2 + 2, x + x_add, y + height);
|
|
}
|
|
break;
|
|
|
|
case Function_end:
|
|
{
|
|
if(loop)
|
|
y_add = height / 2 - 1;
|
|
painter->drawLine(x + x_add, y, x + x_add, y + height - y_add);
|
|
painter->drawLine(x + x_add, y + height - y_add, x + x_add + line_width, y + height - y_add);
|
|
}
|
|
break;
|
|
|
|
case Function_none:
|
|
{
|
|
|
|
}
|
|
break;
|
|
}
|
|
return x_add + line_width + end_add;
|
|
}
|
|
|
|
|
|
/************************************************************************************
|
|
Instructions Management
|
|
***********************************************************************************/
|
|
/**
|
|
* @brief Returns the RVA of count-th instructions before the given instruction RVA.
|
|
*
|
|
* @param[in] rva Instruction RVA
|
|
* @param[in] count Instruction count
|
|
*
|
|
* @return RVA of count-th instructions before the given instruction RVA.
|
|
*/
|
|
int_t Disassembly::getPreviousInstructionRVA(int_t rva, uint_t count)
|
|
{
|
|
QByteArray wBuffer;
|
|
int_t wBottomByteRealRVA;
|
|
int_t wVirtualRVA;
|
|
int_t wMaxByteCountToRead ;
|
|
|
|
wBottomByteRealRVA = (int_t)rva - 16 * (count + 3);
|
|
wBottomByteRealRVA = wBottomByteRealRVA < 0 ? 0 : wBottomByteRealRVA;
|
|
|
|
wVirtualRVA = (int_t)rva - wBottomByteRealRVA;
|
|
|
|
wMaxByteCountToRead = wVirtualRVA + 1 + 16;
|
|
wBuffer.resize(wMaxByteCountToRead);
|
|
|
|
mMemPage->read(reinterpret_cast<byte_t*>(wBuffer.data()), wBottomByteRealRVA, wMaxByteCountToRead);
|
|
|
|
int_t addr = mDisasm->DisassembleBack(reinterpret_cast<byte_t*>(wBuffer.data()), 0, wMaxByteCountToRead, wVirtualRVA, count);
|
|
|
|
addr += rva - wVirtualRVA;
|
|
|
|
return addr;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Returns the RVA of count-th instructions after the given instruction RVA.
|
|
*
|
|
* @param[in] rva Instruction RVA
|
|
* @param[in] count Instruction count
|
|
*
|
|
* @return RVA of count-th instructions after the given instruction RVA.
|
|
*/
|
|
int_t Disassembly::getNextInstructionRVA(int_t rva, uint_t count)
|
|
{
|
|
QByteArray wBuffer;
|
|
int_t wVirtualRVA = 0;
|
|
int_t wRemainingBytes;
|
|
int_t wMaxByteCountToRead;
|
|
int_t wNewRVA;
|
|
|
|
if(mMemPage->getSize() < (uint_t)rva)
|
|
return rva;
|
|
wRemainingBytes = mMemPage->getSize() - rva;
|
|
|
|
wMaxByteCountToRead = 16 * (count + 1);
|
|
wMaxByteCountToRead = wRemainingBytes > wMaxByteCountToRead ? wMaxByteCountToRead : wRemainingBytes;
|
|
wBuffer.resize(wMaxByteCountToRead);
|
|
|
|
mMemPage->read(reinterpret_cast<byte_t*>(wBuffer.data()), rva, wMaxByteCountToRead);
|
|
|
|
wNewRVA = mDisasm->DisassembleNext(reinterpret_cast<byte_t*>(wBuffer.data()), 0, wMaxByteCountToRead, wVirtualRVA, count);
|
|
wNewRVA += rva;
|
|
|
|
return wNewRVA;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Returns the RVA of count-th instructions before/after (depending on the sign) the given instruction RVA.
|
|
*
|
|
* @param[in] rva Instruction RVA
|
|
* @param[in] count Instruction count
|
|
*
|
|
* @return RVA of count-th instructions before/after the given instruction RVA.
|
|
*/
|
|
int_t Disassembly::getInstructionRVA(int_t index, int_t count)
|
|
{
|
|
int_t wAddr = 0;
|
|
|
|
if(count == 0)
|
|
wAddr = index;
|
|
if(count < 0)
|
|
wAddr = getPreviousInstructionRVA(index, qAbs(count));
|
|
else if(count > 0)
|
|
wAddr = getNextInstructionRVA(index, qAbs(count));
|
|
|
|
|
|
if(wAddr < 0)
|
|
wAddr = 0;
|
|
else if(wAddr > getRowCount() - 1)
|
|
wAddr = getRowCount() - 1;
|
|
|
|
return wAddr;
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Disassembles the instruction at the given RVA.
|
|
*
|
|
* @param[in] rva RVA of instruction to disassemble
|
|
*
|
|
* @return Return the disassembled instruction.
|
|
*/
|
|
Instruction_t Disassembly::DisassembleAt(int_t rva)
|
|
{
|
|
QByteArray wBuffer;
|
|
int_t base = mMemPage->getBase();
|
|
int_t wMaxByteCountToRead = 16 * 2;
|
|
|
|
// Bounding
|
|
//TODO: fix problems with negative sizes
|
|
int_t size = getSize();
|
|
if(!size)
|
|
size = rva;
|
|
|
|
wMaxByteCountToRead = wMaxByteCountToRead > (size - rva) ? (size - rva) : wMaxByteCountToRead;
|
|
|
|
wBuffer.resize(wMaxByteCountToRead);
|
|
|
|
mMemPage->read(reinterpret_cast<byte_t*>(wBuffer.data()), rva, wMaxByteCountToRead);
|
|
|
|
return mDisasm->DisassembleAt(reinterpret_cast<byte_t*>(wBuffer.data()), wMaxByteCountToRead, 0, base, rva);
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Disassembles the instruction count instruction afterc the instruction at the given RVA.
|
|
* Count can be positive or negative.
|
|
*
|
|
* @param[in] rva RVA of reference instruction
|
|
* @param[in] count Number of instruction
|
|
*
|
|
* @return Return the disassembled instruction.
|
|
*/
|
|
Instruction_t Disassembly::DisassembleAt(int_t rva, int_t count)
|
|
{
|
|
rva = getNextInstructionRVA(rva, count);
|
|
return DisassembleAt(rva);
|
|
}
|
|
|
|
|
|
/************************************************************************************
|
|
Selection Management
|
|
************************************************************************************/
|
|
void Disassembly::expandSelectionUpTo(int_t to)
|
|
{
|
|
if(to < mSelection.firstSelectedIndex)
|
|
{
|
|
mSelection.fromIndex = to;
|
|
}
|
|
else if(to > mSelection.firstSelectedIndex)
|
|
{
|
|
mSelection.toIndex = to;
|
|
}
|
|
else if(to == mSelection.firstSelectedIndex)
|
|
{
|
|
setSingleSelection(to);
|
|
}
|
|
}
|
|
|
|
void Disassembly::setSingleSelection(int_t index)
|
|
{
|
|
mSelection.firstSelectedIndex = index;
|
|
mSelection.fromIndex = index;
|
|
mSelection.toIndex = index;
|
|
emit selectionChanged(rvaToVa(index));
|
|
}
|
|
|
|
|
|
int_t Disassembly::getInitialSelection()
|
|
{
|
|
return mSelection.firstSelectedIndex;
|
|
}
|
|
|
|
int_t Disassembly::getSelectionSize()
|
|
{
|
|
return mSelection.toIndex - mSelection.fromIndex;
|
|
}
|
|
|
|
int_t Disassembly::getSelectionStart()
|
|
{
|
|
return mSelection.fromIndex;
|
|
}
|
|
|
|
int_t Disassembly::getSelectionEnd()
|
|
{
|
|
return mSelection.toIndex;
|
|
}
|
|
|
|
void Disassembly::selectNext(bool expand)
|
|
{
|
|
int_t wAddr;
|
|
int_t wStart = getInstructionRVA(getSelectionStart(), 1) - 1;
|
|
if(expand)
|
|
{
|
|
if(getSelectionEnd() == getInitialSelection() && wStart != getSelectionEnd()) //decrease down
|
|
{
|
|
wAddr = getInstructionRVA(getSelectionStart(), 1);
|
|
expandSelectionUpTo(wAddr);
|
|
}
|
|
else //expand down
|
|
{
|
|
wAddr = getSelectionEnd() + 1;
|
|
int_t wInstrSize = getInstructionRVA(wAddr, 1) - wAddr - 1;
|
|
expandSelectionUpTo(wAddr + wInstrSize);
|
|
}
|
|
}
|
|
else //select next instruction
|
|
{
|
|
wAddr = getSelectionEnd() + 1;
|
|
setSingleSelection(wAddr);
|
|
int_t wInstrSize = getInstructionRVA(wAddr, 1) - wAddr - 1;
|
|
expandSelectionUpTo(wAddr + wInstrSize);
|
|
}
|
|
}
|
|
|
|
|
|
void Disassembly::selectPrevious(bool expand)
|
|
{
|
|
int_t wAddr;
|
|
int_t wStart = getInstructionRVA(getSelectionStart(), 1) - 1;
|
|
if(expand)
|
|
{
|
|
if(getSelectionStart() == getInitialSelection() && wStart != getSelectionEnd()) //decrease up
|
|
{
|
|
wAddr = getInstructionRVA(getSelectionEnd() + 1, -2);
|
|
int_t wInstrSize = getInstructionRVA(wAddr, 1) - wAddr - 1;
|
|
expandSelectionUpTo(wAddr + wInstrSize);
|
|
}
|
|
else //expand up
|
|
{
|
|
wAddr = getInstructionRVA(wStart + 1, -2);
|
|
expandSelectionUpTo(wAddr);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wAddr = getInstructionRVA(getSelectionStart(), -1);
|
|
setSingleSelection(wAddr);
|
|
int_t wInstrSize = getInstructionRVA(wAddr, 1) - wAddr - 1;
|
|
expandSelectionUpTo(wAddr + wInstrSize);
|
|
}
|
|
}
|
|
|
|
|
|
bool Disassembly::isSelected(int_t base, int_t offset)
|
|
{
|
|
int_t wAddr = base;
|
|
|
|
if(offset < 0)
|
|
wAddr = getPreviousInstructionRVA(getTableOffset(), offset);
|
|
else if(offset > 0)
|
|
wAddr = getNextInstructionRVA(getTableOffset(), offset);
|
|
|
|
if(wAddr >= mSelection.fromIndex && wAddr <= mSelection.toIndex)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
bool Disassembly::isSelected(QList<Instruction_t>* buffer, int index)
|
|
{
|
|
if(buffer->size() > 0 && index >= 0 && index < buffer->size())
|
|
{
|
|
if((int_t)buffer->at(index).rva >= mSelection.fromIndex && (int_t)buffer->at(index).rva <= mSelection.toIndex)
|
|
return true;
|
|
else
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
|
|
/************************************************************************************
|
|
Update/Reload/Refresh/Repaint
|
|
************************************************************************************/
|
|
|
|
void Disassembly::prepareDataCount(int_t wRVA, int wCount, QList<Instruction_t>* instBuffer)
|
|
{
|
|
instBuffer->clear();
|
|
Instruction_t wInst;
|
|
for(int wI = 0; wI < wCount; wI++)
|
|
{
|
|
wInst = DisassembleAt(wRVA);
|
|
instBuffer->append(wInst);
|
|
wRVA += wInst.length;
|
|
}
|
|
}
|
|
|
|
void Disassembly::prepareDataRange(int_t startRva, int_t endRva, QList<Instruction_t>* instBuffer)
|
|
{
|
|
if(startRva == endRva)
|
|
prepareDataCount(startRva, 1, instBuffer);
|
|
else
|
|
{
|
|
int wCount = 0;
|
|
int_t addr = startRva;
|
|
while(addr < endRva)
|
|
{
|
|
addr = getNextInstructionRVA(addr, 1);
|
|
wCount++;
|
|
}
|
|
if(addr - 1 != endRva)
|
|
wCount--;
|
|
prepareDataCount(startRva, wCount, instBuffer);
|
|
}
|
|
}
|
|
|
|
void Disassembly::prepareData()
|
|
{
|
|
int_t wViewableRowsCount = getViewableRowsCount();
|
|
|
|
int_t wAddrPrev = getTableOffset();
|
|
int_t wAddr = wAddrPrev;
|
|
|
|
int wCount = 0;
|
|
|
|
for(int wI = 0; wI < wViewableRowsCount && getRowCount() > 0; wI++)
|
|
{
|
|
wAddrPrev = wAddr;
|
|
wAddr = getNextInstructionRVA(wAddr, 1);
|
|
|
|
if(wAddr == wAddrPrev)
|
|
{
|
|
break;
|
|
}
|
|
|
|
wCount++;
|
|
}
|
|
|
|
setNbrOfLineToPrint(wCount);
|
|
|
|
prepareDataCount(getTableOffset(), wCount, &mInstBuffer);
|
|
}
|
|
|
|
void Disassembly::reloadData()
|
|
{
|
|
emit selectionChanged(rvaToVa(mSelection.firstSelectedIndex));
|
|
AbstractTableView::reloadData();
|
|
}
|
|
|
|
|
|
/************************************************************************************
|
|
Public Methods
|
|
************************************************************************************/
|
|
uint_t Disassembly::rvaToVa(int_t rva)
|
|
{
|
|
return mMemPage->va(rva);
|
|
}
|
|
|
|
void Disassembly::disassembleAt(int_t parVA, int_t parCIP, bool history, int_t newTableOffset)
|
|
{
|
|
int_t wBase = DbgMemFindBaseAddr(parVA, 0);
|
|
int_t wSize = DbgMemGetPageSize(wBase);
|
|
if(!wBase || !wSize)
|
|
return;
|
|
int_t wRVA = parVA - wBase;
|
|
int_t wCipRva = parCIP - wBase;
|
|
|
|
HistoryData_t newHistory;
|
|
|
|
//VA history
|
|
if(history)
|
|
{
|
|
//truncate everything right from the current VA
|
|
if(mVaHistory.size() && mCurrentVa < mVaHistory.size() - 1) //mCurrentVa is not the last
|
|
mVaHistory.erase(mVaHistory.begin() + mCurrentVa + 1, mVaHistory.end());
|
|
|
|
//NOTE: mCurrentVa always points to the last entry of the list
|
|
|
|
//add the currently selected address to the history
|
|
int_t selectionVA = rvaToVa(getInitialSelection()); //currently selected VA
|
|
int_t selectionTableOffset = getTableOffset();
|
|
if(selectionVA && mVaHistory.size() && mVaHistory.last().va != selectionVA) //do not have 2x the same va in a row
|
|
{
|
|
if(mVaHistory.size() >= 1024) //max 1024 in the history
|
|
{
|
|
mCurrentVa--;
|
|
mVaHistory.erase(mVaHistory.begin()); //remove the oldest element
|
|
}
|
|
mCurrentVa++;
|
|
newHistory.va = selectionVA;
|
|
newHistory.tableOffset = selectionTableOffset;
|
|
mVaHistory.push_back(newHistory);
|
|
}
|
|
}
|
|
|
|
// Set base and size (Useful when memory page changed)
|
|
mMemPage->setAttributes(wBase, wSize);
|
|
|
|
if(mRvaDisplayEnabled && mMemPage->getBase() != mRvaDisplayPageBase)
|
|
mRvaDisplayEnabled = false;
|
|
|
|
setRowCount(wSize);
|
|
|
|
setSingleSelection(wRVA); // Selects disassembled instruction
|
|
int_t wInstrSize = getInstructionRVA(wRVA, 1) - wRVA - 1;
|
|
expandSelectionUpTo(wRVA + wInstrSize);
|
|
|
|
//set CIP rva
|
|
mCipRva = wCipRva;
|
|
|
|
if(newTableOffset == -1) //nothing specified
|
|
{
|
|
// Update table offset depending on the location of the instruction to disassemble
|
|
if(mInstBuffer.size() > 0 && wRVA >= (int_t)mInstBuffer.first().rva && wRVA < (int_t)mInstBuffer.last().rva)
|
|
{
|
|
int wI;
|
|
bool wIsAligned = false;
|
|
|
|
// Check if the new RVA is aligned on an instruction from the cache (buffer)
|
|
for(wI = 0; wI < mInstBuffer.size(); wI++)
|
|
{
|
|
if(mInstBuffer.at(wI).rva == wRVA)
|
|
{
|
|
wIsAligned = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(wIsAligned == true)
|
|
{
|
|
repaint();
|
|
}
|
|
else
|
|
{
|
|
setTableOffset(wRVA);
|
|
}
|
|
}
|
|
else if(mInstBuffer.size() > 0 && wRVA == (int_t)mInstBuffer.last().rva)
|
|
{
|
|
setTableOffset(mInstBuffer.first().rva + mInstBuffer.first().length);
|
|
}
|
|
else
|
|
{
|
|
setTableOffset(wRVA);
|
|
}
|
|
|
|
if(history)
|
|
{
|
|
//new disassembled address
|
|
newHistory.va = parVA;
|
|
newHistory.tableOffset = getTableOffset();
|
|
if(mVaHistory.size())
|
|
{
|
|
if(mVaHistory.last().va != parVA) //not 2x the same va in history
|
|
{
|
|
if(mVaHistory.size() >= 1024) //max 1024 in the history
|
|
{
|
|
mCurrentVa--;
|
|
mVaHistory.erase(mVaHistory.begin()); //remove the oldest element
|
|
}
|
|
mCurrentVa++;
|
|
mVaHistory.push_back(newHistory); //add a va to the history
|
|
}
|
|
}
|
|
else //the list is empty
|
|
mVaHistory.push_back(newHistory);
|
|
}
|
|
}
|
|
else //specified new table offset
|
|
setTableOffset(newTableOffset);
|
|
|
|
/*
|
|
//print history
|
|
if(history)
|
|
{
|
|
QString strList = "";
|
|
for(int i=0; i<mVaHistory.size(); i++)
|
|
strList += QString().sprintf("[%d]:%p,%p\n", i, mVaHistory.at(i).va, mVaHistory.at(i).tableOffset);
|
|
MessageBoxA(GuiGetWindowHandle(), strList.toUtf8().constData(), QString().sprintf("mCurrentVa=%d", mCurrentVa).toUtf8().constData(), MB_ICONINFORMATION);
|
|
}
|
|
*/
|
|
emit disassembledAt(parVA, parCIP, history, newTableOffset);
|
|
reloadData();
|
|
|
|
}
|
|
|
|
QList<Instruction_t>* Disassembly::instructionsBuffer()
|
|
{
|
|
return &mInstBuffer;
|
|
}
|
|
|
|
const int_t Disassembly::currentEIP() const
|
|
{
|
|
return mCipRva;
|
|
}
|
|
|
|
|
|
void Disassembly::disassembleAt(int_t parVA, int_t parCIP)
|
|
{
|
|
disassembleAt(parVA, parCIP, true, -1);
|
|
}
|
|
|
|
|
|
void Disassembly::disassembleClear()
|
|
{
|
|
mHighlightingMode = false;
|
|
mHighlightToken.value.value = 0;
|
|
mHighlightToken.text = "";
|
|
historyClear();
|
|
mMemPage->setAttributes(0, 0);
|
|
setRowCount(0);
|
|
reloadData();
|
|
}
|
|
|
|
|
|
void Disassembly::debugStateChangedSlot(DBGSTATE state)
|
|
{
|
|
switch(state)
|
|
{
|
|
case stopped:
|
|
disassembleClear();
|
|
break;
|
|
case paused:
|
|
mIsRunning = false;
|
|
break;
|
|
case running:
|
|
mIsRunning = true;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
const int_t Disassembly::getBase() const
|
|
{
|
|
return mMemPage->getBase();
|
|
}
|
|
|
|
int_t Disassembly::getSize()
|
|
{
|
|
return mMemPage->getSize();
|
|
}
|
|
|
|
void Disassembly::historyClear()
|
|
{
|
|
mVaHistory.clear(); //clear history for new targets
|
|
mCurrentVa = 0;
|
|
}
|
|
|
|
void Disassembly::historyPrevious()
|
|
{
|
|
if(!mCurrentVa || !mVaHistory.size()) //we are at the earliest history entry
|
|
return;
|
|
mCurrentVa--;
|
|
disassembleAt(mVaHistory.at(mCurrentVa).va, rvaToVa(mCipRva), false, mVaHistory.at(mCurrentVa).tableOffset);
|
|
}
|
|
|
|
void Disassembly::historyNext()
|
|
{
|
|
int size = mVaHistory.size();
|
|
if(!size || mCurrentVa >= mVaHistory.size() - 1) //we are at the newest history entry
|
|
return;
|
|
mCurrentVa++;
|
|
disassembleAt(mVaHistory.at(mCurrentVa).va, rvaToVa(mCipRva), false, mVaHistory.at(mCurrentVa).tableOffset);
|
|
}
|
|
|
|
bool Disassembly::historyHasPrevious()
|
|
{
|
|
if(!mCurrentVa || !mVaHistory.size()) //we are at the earliest history entry
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool Disassembly::historyHasNext()
|
|
{
|
|
int size = mVaHistory.size();
|
|
if(!size || mCurrentVa >= mVaHistory.size() - 1) //we are at the newest history entry
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
QString Disassembly::getAddrText(int_t cur_addr, char label[MAX_LABEL_SIZE])
|
|
{
|
|
QString addrText = "";
|
|
if(mRvaDisplayEnabled) //RVA display
|
|
{
|
|
int_t rva = cur_addr - mRvaDisplayBase;
|
|
if(rva == 0)
|
|
{
|
|
#ifdef _WIN64
|
|
addrText = "$ ==> ";
|
|
#else
|
|
addrText = "$ ==> ";
|
|
#endif //_WIN64
|
|
}
|
|
else if(rva > 0)
|
|
{
|
|
#ifdef _WIN64
|
|
addrText = "$+" + QString("%1").arg(rva, -15, 16, QChar(' ')).toUpper();
|
|
#else
|
|
addrText = "$+" + QString("%1").arg(rva, -7, 16, QChar(' ')).toUpper();
|
|
#endif //_WIN64
|
|
}
|
|
else if(rva < 0)
|
|
{
|
|
#ifdef _WIN64
|
|
addrText = "$-" + QString("%1").arg(-rva, -15, 16, QChar(' ')).toUpper();
|
|
#else
|
|
addrText = "$-" + QString("%1").arg(-rva, -7, 16, QChar(' ')).toUpper();
|
|
#endif //_WIN64
|
|
}
|
|
}
|
|
addrText += QString("%1").arg(cur_addr, sizeof(int_t) * 2, 16, QChar('0')).toUpper();
|
|
char label_[MAX_LABEL_SIZE] = "";
|
|
if(DbgGetLabelAt(cur_addr, SEG_DEFAULT, label_)) //has label
|
|
{
|
|
char module[MAX_MODULE_SIZE] = "";
|
|
if(DbgGetModuleAt(cur_addr, module) && !QString(label_).startsWith("JMP.&"))
|
|
addrText += " <" + QString(module) + "." + QString(label_) + ">";
|
|
else
|
|
addrText += " <" + QString(label_) + ">";
|
|
}
|
|
else
|
|
*label_ = 0;
|
|
if(label)
|
|
strcpy_s(label, MAX_LABEL_SIZE, label_);
|
|
return addrText;
|
|
}
|