Compare commits
12 Commits
e7995ffd53
...
b7347f4506
Author | SHA1 | Date |
---|---|---|
Duncan Ogilvie | b7347f4506 | |
Duncan Ogilvie | d162dd1adc | |
Duncan Ogilvie | 4802cb008b | |
Duncan Ogilvie | b0e4888c5f | |
dad | 7de1649159 | |
dad | ceb2de32fb | |
dad | 8d182a977e | |
Duncan Ogilvie | 5bbd8f6f69 | |
shocoman | 6d0656b5b8 | |
torusrxxx | 79830fd093 | |
torusrxxx | 5dda6eb13a | |
shocoman | bb56223bd0 |
|
@ -248,12 +248,16 @@ void ReferenceView::referenceContextMenu(QMenu* wMenu)
|
|||
|
||||
void ReferenceView::followAddress()
|
||||
{
|
||||
DbgCmdExecDirect(QString("disasm " + mCurList->getCellContent(mCurList->getInitialSelection(), 0)));
|
||||
int index = mCurList->getInitialSelection();
|
||||
searchSelectionChanged(index);
|
||||
DbgCmdExecDirect(QString("disasm " + mCurList->getCellContent(index, 0)));
|
||||
}
|
||||
|
||||
void ReferenceView::followDumpAddress()
|
||||
{
|
||||
DbgCmdExecDirect(QString("dump " + mCurList->getCellContent(mCurList->getInitialSelection(), 0)));
|
||||
int index = mCurList->getInitialSelection();
|
||||
searchSelectionChanged(index);
|
||||
DbgCmdExecDirect(QString("dump " + mCurList->getCellContent(index, 0)));
|
||||
}
|
||||
|
||||
void ReferenceView::followApiAddress()
|
||||
|
|
|
@ -1052,6 +1052,7 @@ void CPUDisassembly::gotoPreviousReferenceSlot()
|
|||
if(index > 0 && addr == rvaToVa(getInitialSelection()))
|
||||
DbgValToString("$__disasm_refindex", index - 1);
|
||||
gotoAddress(DbgValFromString("refsearch.addr($__disasm_refindex)"));
|
||||
GuiReferenceSetSingleSelection(int(DbgEval("$__disasm_refindex")), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1063,6 +1064,7 @@ void CPUDisassembly::gotoNextReferenceSlot()
|
|||
if(index + 1 < count && addr == rvaToVa(getInitialSelection()))
|
||||
DbgValToString("$__disasm_refindex", index + 1);
|
||||
gotoAddress(DbgValFromString("refsearch.addr($__disasm_refindex)"));
|
||||
GuiReferenceSetSingleSelection(int(DbgEval("$__disasm_refindex")), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -614,6 +614,7 @@ void CPUDump::gotoPreviousReferenceSlot()
|
|||
if(index > 0 && addr == rvaToVa(getInitialSelection()))
|
||||
DbgValToString("$__dump_refindex", index - 1);
|
||||
DbgCmdExec("dump refsearch.addr($__dump_refindex)");
|
||||
GuiReferenceSetSingleSelection(int(DbgEval("$__dump_refindex")), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -625,6 +626,7 @@ void CPUDump::gotoNextReferenceSlot()
|
|||
if(index + 1 < count && addr == rvaToVa(getInitialSelection()))
|
||||
DbgValToString("$__dump_refindex", index + 1);
|
||||
DbgCmdExec("dump refsearch.addr($__dump_refindex)");
|
||||
GuiReferenceSetSingleSelection(int(DbgEval("$__dump_refindex")), false);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -85,10 +85,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget* parent)
|
|||
//colorsUpdatedSlot(); <-- already called somewhere
|
||||
}
|
||||
|
||||
DisassemblerGraphView::~DisassemblerGraphView()
|
||||
{
|
||||
delete this->highlight_token;
|
||||
}
|
||||
DisassemblerGraphView::~DisassemblerGraphView() {}
|
||||
|
||||
void DisassemblerGraphView::resetGraph()
|
||||
{
|
||||
|
@ -96,7 +93,8 @@ void DisassemblerGraphView::resetGraph()
|
|||
this->ready = false;
|
||||
this->viewportReady = false;
|
||||
this->desired_pos = nullptr;
|
||||
this->highlight_token = nullptr;
|
||||
this->mHighlightToken = ZydisTokenizer::SingleToken();
|
||||
this->mHighlightingModeEnabled = false;
|
||||
this->cur_instr = 0;
|
||||
this->scroll_base_x = 0;
|
||||
this->scroll_base_y = 0;
|
||||
|
@ -851,6 +849,19 @@ void DisassemblerGraphView::paintEvent(QPaintEvent* event)
|
|||
paintZoom(p, viewportRect, xofs, yofs);
|
||||
}
|
||||
|
||||
// while selecting a token to highlight, draw a thin 2px red border around the viewport
|
||||
if(!saveGraph && mHighlightingModeEnabled)
|
||||
{
|
||||
QPainter p(this->viewport());
|
||||
QPen pen(Qt::red);
|
||||
pen.setWidth(2);
|
||||
p.setPen(pen);
|
||||
p.setBrush(Qt::NoBrush); // don't fill the background
|
||||
QRect viewportRect = this->viewport()->rect();
|
||||
viewportRect.adjust(1, 1, -1, -1);
|
||||
p.drawRect(viewportRect);
|
||||
}
|
||||
|
||||
if(saveGraph)
|
||||
{
|
||||
//TODO: speed up large graph saving or show gif loader so it won't look like it has crashed
|
||||
|
@ -990,16 +1001,13 @@ duint DisassemblerGraphView::getInstrForMouseEvent(QMouseEvent* event)
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool DisassemblerGraphView::getTokenForMouseEvent(QMouseEvent* event, Token & tokenOut)
|
||||
bool DisassemblerGraphView::getTokenForMouseEvent(QMouseEvent* event, ZydisTokenizer::SingleToken & tokenOut)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
Q_UNUSED(tokenOut);
|
||||
/* TODO
|
||||
//Convert coordinates to system used in blocks
|
||||
int xofs = this->horizontalScrollBar()->value();
|
||||
int yofs = this->verticalScrollBar()->value();
|
||||
int x = event->x() + xofs - this->renderXOfs;
|
||||
int y = event->y() + yofs - this->renderYOfs;
|
||||
int x = (event->x() + xofs - this->renderXOfs) / zoomLevel;
|
||||
int y = (event->y() + yofs - this->renderYOfs) / zoomLevel;
|
||||
|
||||
//Check each block for hits
|
||||
for(auto & blockIt : this->blocks)
|
||||
|
@ -1016,44 +1024,46 @@ bool DisassemblerGraphView::getTokenForMouseEvent(QMouseEvent* event, Token & to
|
|||
//Compute row and column within text
|
||||
int col = int(blockx / this->charWidth);
|
||||
int row = int(blocky / this->charHeight);
|
||||
|
||||
//Check tokens to see if one was clicked
|
||||
int cur_row = 0;
|
||||
for(auto & line : block.block.header_text.tokens)
|
||||
int selectedCodeRow = row - block.block.header_text.lines.size();
|
||||
if(selectedCodeRow < 0)
|
||||
return false; // skip the header
|
||||
|
||||
int rowIndex = 0;
|
||||
for(auto & instr : block.block.instrs)
|
||||
{
|
||||
if(cur_row == row)
|
||||
int lineCount = instr.text.lines.size();
|
||||
|
||||
if(rowIndex + lineCount > selectedCodeRow)
|
||||
{
|
||||
for(Token & token : line)
|
||||
// instruction found, try to get the row and precise token from it
|
||||
|
||||
size_t instrRow = selectedCodeRow - rowIndex;
|
||||
if(instrRow < instr.text.lineTokens.size())
|
||||
{
|
||||
if((col >= token.start) && (col < (token.start + token.length)))
|
||||
auto & instrToken = instr.text.lineTokens.at(instrRow);
|
||||
int x = instrToken.x; // skip the breakpoint/CIP mark and RVA prefix
|
||||
|
||||
for(auto & token : instrToken.tokens)
|
||||
{
|
||||
//Clicked on a token
|
||||
tokenOut = token;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
cur_row += 1;
|
||||
}
|
||||
for(Instr & instr : block.block.instrs)
|
||||
{
|
||||
for(auto & line : instr.text.tokens)
|
||||
{
|
||||
if(cur_row == row)
|
||||
{
|
||||
for(Token & token : line)
|
||||
{
|
||||
if((col >= token.start) && (col < (token.start + token.length)))
|
||||
auto tokenLength = token.text.size();
|
||||
if(col >= x && col < x + tokenLength)
|
||||
{
|
||||
//Clicked on a token
|
||||
tokenOut = token;
|
||||
return true;
|
||||
}
|
||||
x += tokenLength;
|
||||
}
|
||||
}
|
||||
cur_row += 1;
|
||||
|
||||
return false; // selected area doesn't have associated tokens
|
||||
}
|
||||
|
||||
rowIndex += lineCount;
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1106,44 +1116,82 @@ void DisassemblerGraphView::mousePressEvent(QMouseEvent* event)
|
|||
wMenu.exec(event->globalPos()); //execute context menu
|
||||
}
|
||||
}
|
||||
else if((event->button() == Qt::LeftButton || event->button() == Qt::RightButton) && inBlock)
|
||||
else if(event->button() & (Qt::LeftButton | Qt::RightButton))
|
||||
{
|
||||
//Check for click on a token and highlight it
|
||||
Token token;
|
||||
delete this->highlight_token;
|
||||
if(this->getTokenForMouseEvent(event, token))
|
||||
this->highlight_token = HighlightToken::fromToken(token);
|
||||
else
|
||||
this->highlight_token = nullptr;
|
||||
// the highlighting behaviour mostly mimics that of CPUDisassembly
|
||||
auto oldHighlightToken = mHighlightToken;
|
||||
if((event->button() == Qt::RightButton || inBlock) && mHighlightingModeEnabled)
|
||||
mHighlightToken = ZydisTokenizer::SingleToken();
|
||||
bool overrideCtxMenu = mHighlightingModeEnabled; // "intercept" the standard ctx menu
|
||||
|
||||
//Update current instruction
|
||||
duint instr = this->getInstrForMouseEvent(event);
|
||||
if(instr != 0)
|
||||
if(inBlock)
|
||||
{
|
||||
this->cur_instr = instr;
|
||||
emit selectionChanged(instr);
|
||||
//Check for click on a token and highlight it
|
||||
ZydisTokenizer::SingleToken currentToken;
|
||||
if(this->getTokenForMouseEvent(event, currentToken))
|
||||
{
|
||||
bool isHighlightable = ZydisTokenizer::IsHighlightableToken(currentToken);
|
||||
|
||||
if(isHighlightable && (mPermanentHighlightingMode || mHighlightingModeEnabled))
|
||||
{
|
||||
if(oldHighlightToken == currentToken && event->button() == Qt::LeftButton)
|
||||
// on LMB, deselect an already highlighted token
|
||||
mHighlightToken = ZydisTokenizer::SingleToken();
|
||||
else
|
||||
mHighlightToken = currentToken;
|
||||
}
|
||||
}
|
||||
|
||||
//Update current instruction when the highlighting mode is off
|
||||
duint instr = this->getInstrForMouseEvent(event);
|
||||
if(instr != 0 && !mHighlightingModeEnabled)
|
||||
{
|
||||
this->cur_instr = instr;
|
||||
emit selectionChanged(instr);
|
||||
}
|
||||
|
||||
this->viewport()->update();
|
||||
}
|
||||
|
||||
this->viewport()->update();
|
||||
if(event->button() == Qt::LeftButton && !inBlock)
|
||||
{
|
||||
//Left click outside any block, enter scrolling mode
|
||||
this->scroll_base_x = event->x();
|
||||
this->scroll_base_y = event->y();
|
||||
this->scroll_mode = true;
|
||||
this->setCursor(Qt::ClosedHandCursor);
|
||||
this->viewport()->grabMouse();
|
||||
}
|
||||
else
|
||||
{
|
||||
// preserve the Highlighting mode only when scrolling with LMB
|
||||
mHighlightingModeEnabled = false;
|
||||
}
|
||||
|
||||
// if the highlighting has changed, show it on the current graph
|
||||
if(!ZydisTokenizer::TokenEquals(&oldHighlightToken, &mHighlightToken))
|
||||
for(auto & blockIt : this->blocks)
|
||||
for(auto & instr : blockIt.second.block.instrs)
|
||||
instr.text.updateHighlighting(mHighlightToken,
|
||||
mInstructionHighlightColor,
|
||||
mInstructionHighlightBackgroundColor);
|
||||
|
||||
if(event->button() == Qt::RightButton)
|
||||
{
|
||||
showContextMenu(event);
|
||||
if(overrideCtxMenu && !mHighlightToken.text.isEmpty())
|
||||
{
|
||||
// show the "copy highlighted token" context menu
|
||||
QMenu wMenu(this);
|
||||
mHighlightMenuBuilder->build(&wMenu);
|
||||
wMenu.exec(event->globalPos());
|
||||
lastRightClickPosition.pos = {};
|
||||
}
|
||||
else if(!overrideCtxMenu)
|
||||
{
|
||||
showContextMenu(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(event->button() == Qt::LeftButton)
|
||||
{
|
||||
//Left click outside any block, enter scrolling mode
|
||||
this->scroll_base_x = event->x();
|
||||
this->scroll_base_y = event->y();
|
||||
this->scroll_mode = true;
|
||||
this->setCursor(Qt::ClosedHandCursor);
|
||||
this->viewport()->grabMouse();
|
||||
}
|
||||
else if(event->button() == Qt::RightButton)
|
||||
{
|
||||
showContextMenu(event);
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::mouseMoveEvent(QMouseEvent* event)
|
||||
|
@ -1963,7 +2011,6 @@ bool DisassemblerGraphView::navigate(duint addr)
|
|||
{
|
||||
this->function = func;
|
||||
this->cur_instr = instr;
|
||||
this->highlight_token = nullptr;
|
||||
this->ready = false;
|
||||
this->desired_pos = nullptr;
|
||||
this->viewport()->update();
|
||||
|
@ -1997,6 +2044,7 @@ void DisassemblerGraphView::setGraphLayout(DisassemblerGraphView::LayoutType lay
|
|||
void DisassemblerGraphView::tokenizerConfigUpdatedSlot()
|
||||
{
|
||||
disasm.UpdateConfig();
|
||||
mPermanentHighlightingMode = ConfigBool("Disassembler", "PermanentHighlightingMode");
|
||||
loadCurrentGraph();
|
||||
}
|
||||
|
||||
|
@ -2036,7 +2084,11 @@ void DisassemblerGraphView::loadCurrentGraph()
|
|||
block.true_path = node.brtrue;
|
||||
block.terminal = node.terminal;
|
||||
block.indirectcall = node.indirectcall;
|
||||
block.header_text = Text(getSymbolicName(block.entry), mLabelColor, mLabelBackgroundColor);
|
||||
|
||||
auto headerRich = Text::makeRich(getSymbolicName(block.entry), mLabelColor, mLabelBackgroundColor);
|
||||
block.header_text = Text();
|
||||
block.header_text.addLine({headerRich}, {});
|
||||
|
||||
{
|
||||
Instr instr;
|
||||
for(const BridgeCFInstruction & nodeInstr : node.instrs)
|
||||
|
@ -2045,18 +2097,17 @@ void DisassemblerGraphView::loadCurrentGraph()
|
|||
currentBlockMap[addr] = block.entry;
|
||||
Instruction_t instrTok = disasm.DisassembleAt((byte_t*)nodeInstr.data, sizeof(nodeInstr.data), 0, addr, false);
|
||||
RichTextPainter::List richText;
|
||||
ZydisTokenizer::TokenToRichText(instrTok.tokens, richText, 0);
|
||||
auto zydisTokens = instrTok.tokens;
|
||||
ZydisTokenizer::TokenToRichText(zydisTokens, richText, nullptr);
|
||||
zydisTokens.x += 1; // account for the breakpoint/CIP mark
|
||||
|
||||
// add rva to node instruction text
|
||||
if(showGraphRva)
|
||||
{
|
||||
RichTextPainter::CustomRichText_t rvaText;
|
||||
rvaText.underline = false;
|
||||
rvaText.textColor = mAddressColor;
|
||||
rvaText.textBackground = mAddressBackgroundColor;
|
||||
rvaText.text = QString().number(instrTok.rva, 16).toUpper().trimmed() + " ";
|
||||
rvaText.flags = rvaText.textBackground.alpha() ? RichTextPainter::FlagAll : RichTextPainter::FlagColor;
|
||||
richText.insert(richText.begin(), rvaText);
|
||||
QString rvaText = QString().number(instrTok.rva, 16).toUpper().trimmed() + " ";
|
||||
auto rvaRich = Text::makeRich(rvaText, mAddressColor, mAddressBackgroundColor);
|
||||
richText.insert(richText.begin(), rvaRich);
|
||||
zydisTokens.x += rvaText.length(); // pad tokens for the highlighting mode
|
||||
}
|
||||
|
||||
auto size = instrTok.length;
|
||||
|
@ -2101,7 +2152,9 @@ void DisassemblerGraphView::loadCurrentGraph()
|
|||
richText.push_back(spaceText);
|
||||
richText.push_back(commentText);
|
||||
}
|
||||
instr.text = Text(richText);
|
||||
instr.text = Text();
|
||||
instr.text.addLine(richText, zydisTokens);
|
||||
instr.text.updateHighlighting(mHighlightToken, mInstructionHighlightColor, mInstructionHighlightBackgroundColor);
|
||||
|
||||
//The summary contains calls, rets, user comments and string references
|
||||
if(!onlySummary ||
|
||||
|
@ -2303,6 +2356,7 @@ void DisassemblerGraphView::setupContextMenu()
|
|||
gotoMenu->addBuilder(childrenAndParentMenu);
|
||||
mMenuBuilder->addMenu(makeMenu(DIcon("goto"), tr("Go to")), gotoMenu);
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("helpmnemonic"), tr("Help on mnemonic"), SLOT(mnemonicHelpSlot()), "ActionHelpOnMnemonic"));
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("highlight"), tr("&Highlighting mode"), SLOT(enableHighlightingModeSlot()), "ActionHighlightingMode"));
|
||||
mMenuBuilder->addSeparator();
|
||||
auto ifgraphZoomMode = [this](QMenu*)
|
||||
{
|
||||
|
@ -2345,6 +2399,17 @@ void DisassemblerGraphView::setupContextMenu()
|
|||
return true;
|
||||
}));
|
||||
|
||||
// Highlighting mode menu
|
||||
mHighlightMenuBuilder = new MenuBuilder(this);
|
||||
mHighlightMenuBuilder->addAction(makeAction(DIcon("copy"), tr("Copy token &text"), SLOT(copyHighlightedTokenTextSlot())));
|
||||
mHighlightMenuBuilder->addAction(makeAction(DIcon("copy_address"), tr("Copy token &value"), SLOT(copyHighlightedTokenValueSlot())), [this](QMenu*)
|
||||
{
|
||||
QString text;
|
||||
if(!getHighlightedTokenValueText(text))
|
||||
return false;
|
||||
return text != mHighlightToken.text;
|
||||
});
|
||||
|
||||
mMenuBuilder->loadFromConfig();
|
||||
}
|
||||
|
||||
|
@ -2412,6 +2477,8 @@ void DisassemblerGraphView::colorsUpdatedSlot()
|
|||
mBreakpointColor = ConfigColor("GraphBreakpointColor");
|
||||
mDisabledBreakpointColor = ConfigColor("GraphDisabledBreakpointColor");
|
||||
mBookmarkBackgroundColor = ConfigColor("DisassemblyBookmarkBackgroundColor");
|
||||
mInstructionHighlightColor = ConfigColor("InstructionHighlightColor");
|
||||
mInstructionHighlightBackgroundColor = ConfigColor("InstructionHighlightBackgroundColor");
|
||||
|
||||
fontChanged();
|
||||
loadCurrentGraph();
|
||||
|
@ -2618,3 +2685,32 @@ void DisassemblerGraphView::dbgStateChangedSlot(DBGSTATE state)
|
|||
this->viewport()->update();
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::copyHighlightedTokenTextSlot()
|
||||
{
|
||||
Bridge::CopyToClipboard(mHighlightToken.text);
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::copyHighlightedTokenValueSlot()
|
||||
{
|
||||
QString text;
|
||||
if(getHighlightedTokenValueText(text))
|
||||
Bridge::CopyToClipboard(text);
|
||||
}
|
||||
|
||||
bool DisassemblerGraphView::getHighlightedTokenValueText(QString & text)
|
||||
{
|
||||
if(mHighlightToken.type <= ZydisTokenizer::TokenType::MnemonicUnusual)
|
||||
return false;
|
||||
duint value = mHighlightToken.value.value;
|
||||
if(!mHighlightToken.value.size && !DbgFunctions()->ValFromString(mHighlightToken.text.toUtf8().constData(), &value))
|
||||
return false;
|
||||
text = ToHexString(value);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::enableHighlightingModeSlot()
|
||||
{
|
||||
mHighlightingModeEnabled = !mHighlightingModeEnabled;
|
||||
this->viewport()->update();
|
||||
}
|
||||
|
|
|
@ -56,61 +56,45 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
struct Token
|
||||
{
|
||||
int start; //token[0]
|
||||
int length; //token[1]
|
||||
QString type; //token[2]
|
||||
duint addr; //token[3]
|
||||
QString name; //token[4]
|
||||
};
|
||||
|
||||
struct HighlightToken
|
||||
{
|
||||
QString type; //highlight_token[0]
|
||||
duint addr; //highlight_token[1]
|
||||
QString name; //highlight_token[2]
|
||||
|
||||
bool equalsToken(const Token & token)
|
||||
{
|
||||
return this->type == token.type &&
|
||||
this->addr == token.addr &&
|
||||
this->name == token.name;
|
||||
}
|
||||
|
||||
static HighlightToken* fromToken(const Token & token)
|
||||
{
|
||||
//TODO: memory leaks
|
||||
auto result = new HighlightToken();
|
||||
result->type = token.type;
|
||||
result->addr = token.addr;
|
||||
result->name = token.name;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
struct Text
|
||||
{
|
||||
// text to render; some words here may be colored (with highlighting mode)
|
||||
std::vector<RichTextPainter::List> lines;
|
||||
// original text (w/o highlighting)
|
||||
std::vector<RichTextPainter::List> backupLines;
|
||||
// tokens for selection in "Highlighting mode"; one "InstructionToken" per line
|
||||
std::vector<ZydisTokenizer::InstructionToken> lineTokens;
|
||||
|
||||
Text() {}
|
||||
|
||||
Text(const QString & text, QColor color, QColor background)
|
||||
void addLine(const RichTextPainter::List & richText, const ZydisTokenizer::InstructionToken & tokens)
|
||||
{
|
||||
lines.push_back(richText);
|
||||
backupLines.push_back(richText);
|
||||
lineTokens.push_back(tokens);
|
||||
}
|
||||
|
||||
void updateHighlighting(const ZydisTokenizer::SingleToken & token, QColor color, QColor background)
|
||||
{
|
||||
// highlight the given token and restore the original colors to the rest of the text
|
||||
for(size_t nLine = 0; nLine < lines.size(); nLine++)
|
||||
for(size_t nRich = 0; nRich < lines[nLine].size(); nRich++)
|
||||
{
|
||||
auto & rt = lines[nLine][nRich], & orig = backupLines[nLine][nRich];
|
||||
rt.textColor = rt.text == token.text ? color : orig.textColor;
|
||||
rt.textBackground = rt.text == token.text ? background : orig.textBackground;
|
||||
}
|
||||
}
|
||||
|
||||
static RichTextPainter::CustomRichText_t makeRich(const QString & text, QColor color, QColor background)
|
||||
{
|
||||
RichTextPainter::List richText;
|
||||
RichTextPainter::CustomRichText_t rt;
|
||||
rt.underline = false;
|
||||
rt.text = text;
|
||||
rt.textColor = color;
|
||||
rt.textBackground = background;
|
||||
rt.flags = rt.textBackground.alpha() ? RichTextPainter::FlagAll : RichTextPainter::FlagColor;
|
||||
richText.push_back(rt);
|
||||
lines.push_back(richText);
|
||||
}
|
||||
|
||||
Text(const RichTextPainter::List & richText)
|
||||
{
|
||||
lines.push_back(richText);
|
||||
return rt;
|
||||
}
|
||||
|
||||
QString ToQString() const
|
||||
|
@ -222,7 +206,7 @@ public:
|
|||
void paintEvent(QPaintEvent* event);
|
||||
bool isMouseEventInBlock(QMouseEvent* event);
|
||||
duint getInstrForMouseEvent(QMouseEvent* event);
|
||||
bool getTokenForMouseEvent(QMouseEvent* event, Token & token);
|
||||
bool getTokenForMouseEvent(QMouseEvent* event, ZydisTokenizer::SingleToken & token);
|
||||
bool find_instr(duint addr, Instr & instr);
|
||||
void mousePressEvent(QMouseEvent* event);
|
||||
void mouseMoveEvent(QMouseEvent* event);
|
||||
|
@ -289,6 +273,9 @@ public slots:
|
|||
void zoomToCursorSlot();
|
||||
void getCurrentGraphSlot(BridgeCFGraphList* graphList);
|
||||
void dbgStateChangedSlot(DBGSTATE state);
|
||||
void copyHighlightedTokenTextSlot();
|
||||
void copyHighlightedTokenValueSlot();
|
||||
void enableHighlightingModeSlot();
|
||||
|
||||
private:
|
||||
bool graphZoomMode;
|
||||
|
@ -324,7 +311,6 @@ private:
|
|||
bool viewportReady;
|
||||
int* desired_pos;
|
||||
std::unordered_map<duint, DisassemblerBlock> blocks;
|
||||
HighlightToken* highlight_token;
|
||||
std::vector<int> col_edge_x;
|
||||
std::vector<int> row_edge_y;
|
||||
CachedFontMetrics* mFontMetrics;
|
||||
|
@ -343,6 +329,11 @@ private:
|
|||
bool mHistoryLock; //Don't add a history while going to previous/next
|
||||
LayoutType layoutType;
|
||||
|
||||
MenuBuilder* mHighlightMenuBuilder;
|
||||
ZydisTokenizer::SingleToken mHighlightToken;
|
||||
bool mHighlightingModeEnabled;
|
||||
bool mPermanentHighlightingMode;
|
||||
|
||||
QAction* mToggleOverview;
|
||||
QAction* mToggleSummary;
|
||||
QAction* mToggleSyncOrigin;
|
||||
|
@ -374,6 +365,8 @@ private:
|
|||
QColor graphNodeColor;
|
||||
QColor graphNodeBackgroundColor;
|
||||
QColor graphCurrentShadowColor;
|
||||
QColor mInstructionHighlightColor;
|
||||
QColor mInstructionHighlightBackgroundColor;
|
||||
|
||||
BridgeCFGraph currentGraph;
|
||||
std::unordered_map<duint, duint> currentBlockMap;
|
||||
|
@ -382,4 +375,5 @@ private:
|
|||
XrefBrowseDialog* mXrefDlg;
|
||||
|
||||
void addReferenceAction(QMenu* menu, duint addr, const QString & description);
|
||||
bool getHighlightedTokenValueText(QString & text);
|
||||
};
|
||||
|
|
|
@ -172,65 +172,71 @@ EditFloatRegister::EditFloatRegister(int RegisterSize, QWidget* parent) :
|
|||
|
||||
void EditFloatRegister::hideUpperPart()
|
||||
{
|
||||
ui->line->hide();
|
||||
ui->labelH0->hide();
|
||||
ui->labelH1->hide();
|
||||
ui->labelH2->hide();
|
||||
ui->labelH3->hide();
|
||||
ui->labelH4->hide();
|
||||
ui->labelH5->hide();
|
||||
ui->labelH6->hide();
|
||||
ui->labelH7->hide();
|
||||
ui->labelH8->hide();
|
||||
ui->labelH9->hide();
|
||||
ui->labelHA->hide();
|
||||
ui->labelHB->hide();
|
||||
ui->labelHC->hide();
|
||||
ui->labelHD->hide();
|
||||
ui->labelHE->hide();
|
||||
ui->hexEdit->hide();
|
||||
ui->shortEdit0->hide();
|
||||
ui->shortEdit1->hide();
|
||||
ui->shortEdit2->hide();
|
||||
ui->shortEdit3->hide();
|
||||
ui->shortEdit4->hide();
|
||||
ui->shortEdit5->hide();
|
||||
ui->shortEdit6->hide();
|
||||
ui->shortEdit7->hide();
|
||||
ui->longEdit0->hide();
|
||||
ui->longEdit1->hide();
|
||||
ui->longEdit2->hide();
|
||||
ui->longEdit3->hide();
|
||||
ui->floatEdit0->hide();
|
||||
ui->floatEdit1->hide();
|
||||
ui->floatEdit2->hide();
|
||||
ui->floatEdit3->hide();
|
||||
ui->doubleEdit0->hide();
|
||||
ui->doubleEdit1->hide();
|
||||
ui->longLongEdit0->hide();
|
||||
ui->longLongEdit1->hide();
|
||||
QWidget* useless_controls[] = {ui->line,
|
||||
ui->labelH0,
|
||||
ui->labelH1,
|
||||
ui->labelH2,
|
||||
ui->labelH3,
|
||||
ui->labelH4,
|
||||
ui->labelH5,
|
||||
ui->labelH6,
|
||||
ui->labelH7,
|
||||
ui->labelH8,
|
||||
ui->labelH9,
|
||||
ui->labelHA,
|
||||
ui->labelHB,
|
||||
ui->labelHC,
|
||||
ui->labelHD,
|
||||
ui->labelHE,
|
||||
ui->hexEdit,
|
||||
ui->shortEdit0,
|
||||
ui->shortEdit1,
|
||||
ui->shortEdit2,
|
||||
ui->shortEdit3,
|
||||
ui->shortEdit4,
|
||||
ui->shortEdit5,
|
||||
ui->shortEdit6,
|
||||
ui->shortEdit7,
|
||||
ui->longEdit0,
|
||||
ui->longEdit1,
|
||||
ui->longEdit2,
|
||||
ui->longEdit3,
|
||||
ui->floatEdit0,
|
||||
ui->floatEdit1,
|
||||
ui->floatEdit2,
|
||||
ui->floatEdit3,
|
||||
ui->doubleEdit0,
|
||||
ui->doubleEdit1,
|
||||
ui->longLongEdit0,
|
||||
ui->longLongEdit1
|
||||
};
|
||||
for(auto all : useless_controls)
|
||||
all->hide();
|
||||
}
|
||||
|
||||
void EditFloatRegister::hideNonMMXPart()
|
||||
{
|
||||
ui->labelL4->hide();
|
||||
ui->labelL5->hide();
|
||||
ui->labelL6->hide();
|
||||
ui->labelL7->hide();
|
||||
ui->labelLC->hide();
|
||||
ui->labelLD->hide();
|
||||
ui->doubleEdit0_2->hide();
|
||||
ui->doubleEdit1_2->hide();
|
||||
ui->longLongEdit0_2->hide();
|
||||
ui->longLongEdit1_2->hide();
|
||||
ui->shortEdit4_2->hide();
|
||||
ui->shortEdit5_2->hide();
|
||||
ui->shortEdit6_2->hide();
|
||||
ui->shortEdit7_2->hide();
|
||||
ui->longEdit2_2->hide();
|
||||
ui->longEdit3_2->hide();
|
||||
ui->floatEdit2_2->hide();
|
||||
ui->floatEdit3_2->hide();
|
||||
QWidget* useless_controls[] = {ui->labelL4,
|
||||
ui->labelL5,
|
||||
ui->labelL6,
|
||||
ui->labelL7,
|
||||
ui->labelLC,
|
||||
ui->labelLD,
|
||||
ui->doubleEdit0_2,
|
||||
ui->doubleEdit1_2,
|
||||
ui->longLongEdit0_2,
|
||||
ui->longLongEdit1_2,
|
||||
ui->shortEdit4_2,
|
||||
ui->shortEdit5_2,
|
||||
ui->shortEdit6_2,
|
||||
ui->shortEdit7_2,
|
||||
ui->longEdit2_2,
|
||||
ui->longEdit3_2,
|
||||
ui->floatEdit2_2,
|
||||
ui->floatEdit3_2
|
||||
};
|
||||
for(auto all : useless_controls)
|
||||
all->hide();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -6,11 +6,12 @@
|
|||
#include "QCompleter"
|
||||
#include "SymbolAutoCompleteModel.h"
|
||||
|
||||
GotoDialog::GotoDialog(QWidget* parent, bool allowInvalidExpression, bool allowInvalidAddress)
|
||||
GotoDialog::GotoDialog(QWidget* parent, bool allowInvalidExpression, bool allowInvalidAddress, bool allowNotDebugging)
|
||||
: QDialog(parent),
|
||||
ui(new Ui::GotoDialog),
|
||||
allowInvalidExpression(allowInvalidExpression),
|
||||
allowInvalidAddress(allowInvalidAddress || allowInvalidExpression)
|
||||
allowInvalidAddress(allowInvalidAddress || allowInvalidExpression),
|
||||
allowNotDebugging(allowNotDebugging)
|
||||
{
|
||||
//setup UI first
|
||||
ui->setupUi(this);
|
||||
|
@ -18,7 +19,7 @@ GotoDialog::GotoDialog(QWidget* parent, bool allowInvalidExpression, bool allowI
|
|||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint | Qt::MSWindowsFixedSizeDialogHint);
|
||||
|
||||
//initialize stuff
|
||||
if(!DbgIsDebugging()) //not debugging
|
||||
if(!allowNotDebugging && !DbgIsDebugging()) //not debugging
|
||||
ui->labelError->setText(tr("<font color='red'><b>Not debugging...</b></font>"));
|
||||
else
|
||||
ui->labelError->setText(tr("<font color='red'><b>Invalid expression...</b></font>"));
|
||||
|
@ -105,7 +106,7 @@ void GotoDialog::expressionChanged(bool validExpression, bool validPointer, dsin
|
|||
}
|
||||
if(expressionText == expression)
|
||||
return;
|
||||
if(!DbgIsDebugging()) //not debugging
|
||||
if(!allowNotDebugging && !DbgIsDebugging()) //not debugging
|
||||
{
|
||||
ui->labelError->setText(tr("<font color='red'><b>Not debugging...</b></font>"));
|
||||
setOkEnabled(false);
|
||||
|
|
|
@ -16,7 +16,7 @@ class GotoDialog : public QDialog
|
|||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GotoDialog(QWidget* parent = 0, bool allowInvalidExpression = false, bool allowInvalidAddress = false);
|
||||
explicit GotoDialog(QWidget* parent = 0, bool allowInvalidExpression = false, bool allowInvalidAddress = false, bool allowNotDebugging = false);
|
||||
~GotoDialog();
|
||||
QString expressionText;
|
||||
duint validRangeStart;
|
||||
|
@ -25,6 +25,7 @@ public:
|
|||
QString modName;
|
||||
bool allowInvalidExpression;
|
||||
bool allowInvalidAddress;
|
||||
bool allowNotDebugging;
|
||||
void showEvent(QShowEvent* event);
|
||||
void hideEvent(QHideEvent* event);
|
||||
void validateExpression(QString expression);
|
||||
|
|
|
@ -126,7 +126,7 @@ MainWindow::MainWindow(QWidget* parent)
|
|||
initMenuApi();
|
||||
Bridge::getBridge()->emitMenuAddToList(this, ui->menuPlugins, GUI_PLUGIN_MENU);
|
||||
|
||||
// Set window title
|
||||
// Set window title to executable name
|
||||
if(BridgeIsProcessElevated())
|
||||
{
|
||||
mWindowMainTitle = tr("%1 [Elevated]").arg(QCoreApplication::applicationName());
|
||||
|
@ -655,10 +655,11 @@ void MainWindow::loadSelectedTheme(bool reloadOnlyStyleCss)
|
|||
{
|
||||
auto style = QTextStream(&cssFile).readAll();
|
||||
cssFile.close();
|
||||
style = style.replace("url(./", QString("url(%1/../themes/%2/").arg(applicationDirPath, selectedTheme));
|
||||
style = style.replace("url(\"./", QString("url(\"%1/../themes/%2/").arg(applicationDirPath, selectedTheme));
|
||||
style = style.replace("url('./", QString("url('%1/../themes/%2/").arg(applicationDirPath, selectedTheme));
|
||||
style = style.replace("$RELPATH", QString("%1/../themes/%2").arg(applicationDirPath, selectedTheme));
|
||||
|
||||
style = style.replace("url(./", QString("url(approot:/themes/%1/").arg(selectedTheme));
|
||||
style = style.replace("url(\"./", QString("url(\"approot:/themes/%1/").arg(selectedTheme));
|
||||
style = style.replace("url('./", QString("url('approot:/themes/%1/").arg(selectedTheme));
|
||||
style = style.replace("$RELPATH", QString("approot:/themes/%1").arg(selectedTheme));
|
||||
qApp->setStyleSheet(style);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,6 +21,18 @@ ReferenceManager::ReferenceManager(QWidget* parent) : QTabWidget(parent)
|
|||
|
||||
ReferenceView* ReferenceManager::currentReferenceView()
|
||||
{
|
||||
//get the current index, disconnects the previous view if it's not the current one, set and connect the new current view, then return it
|
||||
int currentIndex = QTabWidget::currentIndex();
|
||||
|
||||
if(mCurrentReferenceView && mCurrentReferenceView != widget(currentIndex))
|
||||
{
|
||||
mCurrentReferenceView->disconnectBridge();
|
||||
mCurrentReferenceView = qobject_cast<ReferenceView*>(widget(currentIndex));
|
||||
|
||||
if(mCurrentReferenceView)
|
||||
mCurrentReferenceView->connectBridge();
|
||||
}
|
||||
|
||||
return mCurrentReferenceView;
|
||||
}
|
||||
|
||||
|
|
|
@ -1411,7 +1411,7 @@ void TraceBrowser::gotoSlot()
|
|||
{
|
||||
if(mTraceFile == nullptr || mTraceFile->Progress() < 100)
|
||||
return;
|
||||
GotoDialog gotoDlg(this, false, true); // TODO: Cannot use when not debugging
|
||||
GotoDialog gotoDlg(this, false, true, true);
|
||||
if(gotoDlg.exec() == QDialog::Accepted)
|
||||
{
|
||||
auto val = DbgValFromString(gotoDlg.expressionText.toUtf8().constData());
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#pragma once
|
||||
|
||||
#include <QMenu>
|
||||
#include <QAction>
|
||||
#include <functional>
|
||||
#include "Configuration.h"
|
||||
|
@ -12,6 +12,7 @@ using MakeActionFunc1 = std::function<QAction*(const QString &, const SlotFunc &
|
|||
using MakeActionFunc2 = std::function<QAction*(const QIcon &, const QString &, const SlotFunc &)>;
|
||||
using MakeShortcutActionFunc1 = std::function<QAction*(const QString &, const SlotFunc &, const char*)>;
|
||||
using MakeShortcutActionFunc2 = std::function<QAction*(const QIcon &, const QString &, const SlotFunc &, const char*)>;
|
||||
using MakeShortcutDescActionFunc2 = std::function<QAction*(const QIcon &, const QString &, const QString &, const SlotFunc &, const char*)>;
|
||||
using MakeMenuActionFunc1 = std::function<QAction*(QMenu*, const QString &, const SlotFunc &)>;
|
||||
using MakeMenuActionFunc2 = std::function<QAction*(QMenu*, const QIcon &, const QString &, const SlotFunc &)>;
|
||||
using MakeShortcutMenuActionFunc1 = std::function<QAction*(QMenu*, const QString &, const SlotFunc &, const char*)>;
|
||||
|
@ -25,6 +26,7 @@ struct ActionHelperFuncs
|
|||
MakeActionFunc2 makeAction2;
|
||||
MakeShortcutActionFunc1 makeShortcutAction1;
|
||||
MakeShortcutActionFunc2 makeShortcutAction2;
|
||||
MakeShortcutDescActionFunc2 makeShortcutDescAction2;
|
||||
MakeMenuActionFunc1 makeMenuAction1;
|
||||
MakeMenuActionFunc2 makeMenuAction2;
|
||||
MakeShortcutMenuActionFunc1 makeShortcutMenuAction1;
|
||||
|
@ -117,6 +119,12 @@ protected:
|
|||
{
|
||||
return makeShortcutAction(icon, text, slot, shortcut);
|
||||
};
|
||||
funcs.makeShortcutDescAction2 = [this](const QIcon & icon, const QString & text, const QString & description, const SlotFunc & slot, const char* shortcut)
|
||||
{
|
||||
auto action = makeShortcutAction(icon, text, slot, shortcut);
|
||||
action->setStatusTip(description);
|
||||
return action;
|
||||
};
|
||||
funcs.makeMenuAction1 = [this](QMenu * menu, const QString & text, const SlotFunc & slot)
|
||||
{
|
||||
return makeMenuAction(menu, text, slot);
|
||||
|
@ -260,4 +268,9 @@ protected:
|
|||
{
|
||||
return funcs.makeShortcutMenuAction2(menu, icon, text, slot, shortcut);
|
||||
}
|
||||
|
||||
inline QAction* makeShortcutDescAction(const QIcon & icon, const QString & text, const QString & description, const SlotFunc & slot, const char* shortcut)
|
||||
{
|
||||
return funcs.makeShortcutDescAction2(icon, text, description, slot, shortcut);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -497,25 +497,57 @@ void Breakpoints::toggleBPByRemoving(BPXTYPE type, duint va)
|
|||
}
|
||||
}
|
||||
|
||||
bool Breakpoints::editBP(BPXTYPE type, const QString & addrText, QWidget* widget)
|
||||
bool Breakpoints::editBP(BPXTYPE type, const QString & addrText, QWidget* widget, const QString & createCommand)
|
||||
{
|
||||
BRIDGEBP bridgebp;
|
||||
if(type != bp_dll)
|
||||
BRIDGEBP bridgebp = {};
|
||||
bool found = false;
|
||||
if(type == bp_dll)
|
||||
{
|
||||
duint addr = addrText.toULongLong(nullptr, 16);
|
||||
if(!DbgFunctions()->GetBridgeBp(type, addr, &bridgebp))
|
||||
return false;
|
||||
found = DbgFunctions()->GetBridgeBp(type, reinterpret_cast<duint>(addrText.toUtf8().constData()), &bridgebp);
|
||||
}
|
||||
else if(!DbgFunctions()->GetBridgeBp(type, reinterpret_cast<duint>(addrText.toUtf8().constData()), &bridgebp))
|
||||
else
|
||||
{
|
||||
found = DbgFunctions()->GetBridgeBp(type, (duint)addrText.toULongLong(nullptr, 16), &bridgebp);
|
||||
}
|
||||
|
||||
if(!createCommand.isEmpty() && !found)
|
||||
{
|
||||
// Create a dummy BRIDGEBP to edit
|
||||
bridgebp.type = type;
|
||||
if(type == bp_dll)
|
||||
{
|
||||
strncpy_s(bridgebp.mod, addrText.toUtf8().constData(), _TRUNCATE);
|
||||
}
|
||||
else
|
||||
{
|
||||
bridgebp.addr = (duint)addrText.toULongLong(nullptr, 16);
|
||||
}
|
||||
}
|
||||
else if(!found)
|
||||
{
|
||||
// Fail if the breakpoint doesn't exist and we cannot create a new one
|
||||
return false;
|
||||
}
|
||||
|
||||
EditBreakpointDialog dialog(widget, bridgebp);
|
||||
if(dialog.exec() != QDialog::Accepted)
|
||||
return false;
|
||||
|
||||
auto bp = dialog.getBp();
|
||||
auto exec = [](const QString & command)
|
||||
{
|
||||
DbgCmdExecDirect(command);
|
||||
return DbgCmdExecDirect(command);
|
||||
};
|
||||
|
||||
// Create the breakpoint if it didn't exist yet
|
||||
if(!createCommand.isEmpty() && !found)
|
||||
{
|
||||
if(!exec(createCommand))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
switch(type)
|
||||
{
|
||||
case bp_normal:
|
||||
|
|
|
@ -31,5 +31,5 @@ public:
|
|||
static void toggleBPByRemoving(BPXTYPE type, duint va);
|
||||
static BPXSTATE BPState(BPXTYPE type, duint va);
|
||||
static bool BPTrival(BPXTYPE type, duint va);
|
||||
static bool editBP(BPXTYPE type, const QString & addrText, QWidget* widget);
|
||||
static bool editBP(BPXTYPE type, const QString & addrText, QWidget* widget, const QString & createCommand = QString());
|
||||
};
|
||||
|
|
|
@ -31,7 +31,7 @@ void CommonActions::build(MenuBuilder* builder, int actions)
|
|||
// Menu action
|
||||
if(actions & ActionDisasm)
|
||||
{
|
||||
builder->addAction(makeShortcutAction(DIcon(ArchValue("processor32", "processor64")), tr("Follow in Disassembler"), std::bind(&CommonActions::followDisassemblySlot, this), "ActionFollowDisasm"), wIsDebugging);
|
||||
builder->addAction(makeShortcutDescAction(DIcon(ArchValue("processor32", "processor64")), tr("Follow in Disassembler"), tr("Show this address in disassembler. Equivalent command \"d address\"."), std::bind(&CommonActions::followDisassemblySlot, this), "ActionFollowDisasm"), wIsDebugging);
|
||||
}
|
||||
if(actions & ActionDisasmData)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ void CommonActions::build(MenuBuilder* builder, int actions)
|
|||
}
|
||||
if(actions & ActionDump)
|
||||
{
|
||||
builder->addAction(makeCommandAction(DIcon("dump"), tr("Follow in Dump"), "dump $"));
|
||||
builder->addAction(makeCommandDescAction(DIcon("dump"), tr("Follow in Dump"), tr("Show the address in dump. Equivalent command \"dump address\"."), "dump $"));
|
||||
}
|
||||
if(actions & ActionDumpData)
|
||||
{
|
||||
|
@ -66,7 +66,7 @@ void CommonActions::build(MenuBuilder* builder, int actions)
|
|||
}
|
||||
if(actions & ActionStackDump)
|
||||
{
|
||||
builder->addAction(makeCommandAction(DIcon("stack"), tr("Follow in Stack"), "sdump $", "ActionFollowStack"), [this](QMenu*)
|
||||
builder->addAction(makeCommandDescAction(DIcon("stack"), tr("Follow in Stack"), tr("Show this address in stack view. Equivalent command \"sdump address\"."), "sdump $", "ActionFollowStack"), [this](QMenu*)
|
||||
{
|
||||
auto start = mGetSelection();
|
||||
return (DbgMemIsValidReadPtr(start) && DbgMemFindBaseAddr(start, 0) == DbgMemFindBaseAddr(DbgValFromString("csp"), 0));
|
||||
|
@ -74,11 +74,11 @@ void CommonActions::build(MenuBuilder* builder, int actions)
|
|||
}
|
||||
if(actions & ActionMemoryMap)
|
||||
{
|
||||
builder->addAction(makeCommandAction(DIcon("memmap_find_address_page"), tr("Follow in Memory Map"), "memmapdump $", "ActionFollowMemMap"), wIsDebugging);
|
||||
builder->addAction(makeCommandDescAction(DIcon("memmap_find_address_page"), tr("Follow in Memory Map"), tr("Show this address in memory map view. Equivalent command \"memmapdump address\"."), "memmapdump $", "ActionFollowMemMap"), wIsDebugging);
|
||||
}
|
||||
if(actions & ActionGraph)
|
||||
{
|
||||
builder->addAction(makeShortcutAction(DIcon("graph"), tr("Graph"), std::bind(&CommonActions::graphSlot, this), "ActionGraph"));
|
||||
builder->addAction(makeShortcutDescAction(DIcon("graph"), tr("Graph"), tr("Show the control flow graph of this function in CPU view. Equivalent command \"graph address\"."), std::bind(&CommonActions::graphSlot, this), "ActionGraph"));
|
||||
}
|
||||
if(actions & ActionBreakpoint)
|
||||
{
|
||||
|
@ -164,19 +164,19 @@ void CommonActions::build(MenuBuilder* builder, int actions)
|
|||
}
|
||||
if(actions & ActionBookmark)
|
||||
{
|
||||
builder->addAction(makeShortcutAction(DIcon("bookmark_toggle"), tr("Toggle Bookmark"), std::bind(&CommonActions::setBookmarkSlot, this), "ActionToggleBookmark"), wIsDebugging);
|
||||
builder->addAction(makeShortcutDescAction(DIcon("bookmark_toggle"), tr("Toggle Bookmark"), tr("Set a bookmark here, or remove bookmark. Equivalent command \"bookmarkset address\"/\"bookmarkdel address\"."), std::bind(&CommonActions::setBookmarkSlot, this), "ActionToggleBookmark"), wIsDebugging);
|
||||
}
|
||||
if(actions & ActionNewOrigin)
|
||||
{
|
||||
builder->addAction(makeShortcutAction(DIcon("neworigin"), tr("Set %1 Here").arg(ArchValue("EIP", "RIP")), std::bind(&CommonActions::setNewOriginHereActionSlot, this), "ActionSetNewOriginHere"));
|
||||
builder->addAction(makeShortcutDescAction(DIcon("neworigin"), tr("Set %1 Here").arg(ArchValue("EIP", "RIP")), tr("Set the next executed instruction to this address. Equivalent command \"mov cip, address\"."), std::bind(&CommonActions::setNewOriginHereActionSlot, this), "ActionSetNewOriginHere"));
|
||||
}
|
||||
if(actions & ActionNewThread)
|
||||
{
|
||||
builder->addAction(makeShortcutAction(DIcon("createthread"), tr("Create New Thread Here"), std::bind(&CommonActions::createThreadSlot, this), "ActionCreateNewThreadHere"));
|
||||
builder->addAction(makeShortcutDescAction(DIcon("createthread"), tr("Create New Thread Here"), tr("Create a new thread at this address. Equivalent command \"createthread address, argument\"."), std::bind(&CommonActions::createThreadSlot, this), "ActionCreateNewThreadHere"));
|
||||
}
|
||||
if(actions & ActionWatch)
|
||||
{
|
||||
builder->addAction(makeCommandAction(DIcon("animal-dog"), ArchValue(tr("&Watch DWORD"), tr("&Watch QWORD")), "AddWatch \"[$]\", \"uint\"", "ActionWatchDwordQword"));
|
||||
builder->addAction(makeCommandDescAction(DIcon("animal-dog"), ArchValue(tr("&Watch DWORD"), tr("&Watch QWORD")), tr("Add the address in the watch view. Equivalent command \"AddWatch [address], \"uint\"\"."), "AddWatch \"[$]\", \"uint\"", "ActionWatchDwordQword"));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -197,7 +197,23 @@ QAction* CommonActions::makeCommandAction(const QIcon & icon, const QString & te
|
|||
});
|
||||
}
|
||||
|
||||
QWidget* CommonActions::widgetparent()
|
||||
static QAction* makeDescActionHelper(QAction* action, const QString & description)
|
||||
{
|
||||
action->setStatusTip(description);
|
||||
return action;
|
||||
}
|
||||
|
||||
QAction* CommonActions::makeCommandDescAction(const QIcon & icon, const QString & text, const QString & description, const char* cmd)
|
||||
{
|
||||
return makeDescActionHelper(makeCommandAction(icon, text, cmd), description);
|
||||
}
|
||||
|
||||
QAction* CommonActions::makeCommandDescAction(const QIcon & icon, const QString & text, const QString & description, const char* cmd, const char* shortcut)
|
||||
{
|
||||
return makeDescActionHelper(makeCommandAction(icon, text, cmd, shortcut), description);
|
||||
}
|
||||
|
||||
QWidget* CommonActions::widgetparent() const
|
||||
{
|
||||
return dynamic_cast<QWidget*>(parent());
|
||||
}
|
||||
|
@ -294,13 +310,14 @@ void CommonActions::setBookmarkSlot()
|
|||
}
|
||||
|
||||
// Give a warning about the selected address is not executable
|
||||
bool CommonActions::WarningBoxNotExecutable(const QString & text, duint wVA)
|
||||
bool CommonActions::WarningBoxNotExecutable(const QString & text, duint wVA) const
|
||||
{
|
||||
if(DbgFunctions()->IsDepEnabled() && !DbgFunctions()->MemIsCodePage(wVA, false))
|
||||
{
|
||||
QMessageBox msgyn(QMessageBox::Warning, tr("Current address is not executable"), text, QMessageBox::Yes | QMessageBox::No, widgetparent());
|
||||
QMessageBox msgyn(QMessageBox::Warning, tr("Address %1 is not executable").arg(ToPtrString(wVA)), text, QMessageBox::Yes | QMessageBox::No, widgetparent());
|
||||
msgyn.setWindowIcon(DIcon("compile-warning"));
|
||||
msgyn.setParent(widgetparent(), Qt::Dialog);
|
||||
msgyn.setDefaultButton(QMessageBox::No);
|
||||
msgyn.setWindowFlags(msgyn.windowFlags() & (~Qt::WindowContextHelpButtonHint));
|
||||
if(msgyn.exec() == QMessageBox::No)
|
||||
return false;
|
||||
|
@ -334,17 +351,23 @@ void CommonActions::editSoftBpActionSlot()
|
|||
{
|
||||
auto selection = mGetSelection();
|
||||
if(selection == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BPXTYPE bpType = DbgGetBpxTypeAt(selection);
|
||||
if((bpType & bp_hardware) == bp_hardware)
|
||||
{
|
||||
Breakpoints::editBP(bp_hardware, ToHexString(selection), widgetparent());
|
||||
}
|
||||
else if((bpType & bp_normal) == bp_normal)
|
||||
{
|
||||
Breakpoints::editBP(bp_normal, ToHexString(selection), widgetparent());
|
||||
}
|
||||
else
|
||||
{
|
||||
DbgCmdExecDirect(QString("bp %1").arg(ToHexString(selection))); //Blocking call
|
||||
if(!Breakpoints::editBP(bp_normal, ToHexString(selection), widgetparent()))
|
||||
Breakpoints::removeBP(bp_normal, selection);
|
||||
auto createCommand = QString("bp %1").arg(ToHexString(selection));
|
||||
Breakpoints::editBP(bp_normal, ToHexString(selection), widgetparent(), createCommand);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,8 @@ public:
|
|||
|
||||
QAction* makeCommandAction(const QIcon & icon, const QString & text, const char* cmd, const char* shortcut);
|
||||
QAction* makeCommandAction(const QIcon & icon, const QString & text, const char* cmd);
|
||||
QAction* makeCommandDescAction(const QIcon & icon, const QString & text, const QString & description, const char* cmd);
|
||||
QAction* makeCommandDescAction(const QIcon & icon, const QString & text, const QString & description, const char* cmd, const char* shortcut);
|
||||
public slots:
|
||||
void followDisassemblySlot();
|
||||
void setLabelSlot();
|
||||
|
@ -72,6 +74,6 @@ public slots:
|
|||
void createThreadSlot();
|
||||
private:
|
||||
GetSelectionFunc mGetSelection;
|
||||
bool WarningBoxNotExecutable(const QString & text, duint wVA);
|
||||
QWidget* widgetparent();
|
||||
bool WarningBoxNotExecutable(const QString & text, duint wVA) const;
|
||||
QWidget* widgetparent() const;
|
||||
};
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <QTextStream>
|
||||
#include <QLibraryInfo>
|
||||
#include <QDebug>
|
||||
#include <QDir>
|
||||
#include "MiscUtil.h"
|
||||
|
||||
MyApplication::MyApplication(int & argc, char** argv)
|
||||
|
@ -181,6 +182,9 @@ int main(int argc, char* argv[])
|
|||
appPalette.setColor(QPalette::Link, ConfigColor("LinkColor"));
|
||||
application.setPalette(appPalette);
|
||||
|
||||
// Register a path prefix for the program main directory
|
||||
QDir::addSearchPath("approot", QApplication::applicationDirPath() + "/..");
|
||||
|
||||
// Load the selected theme
|
||||
MainWindow::loadSelectedTheme(true);
|
||||
|
||||
|
|
Loading…
Reference in New Issue