1
0
Fork 0
x64dbg/src/gui/Src/Gui/BreakpointsView.cpp

779 lines
29 KiB
C++

#include "BreakpointsView.h"
#include "EditBreakpointDialog.h"
#include "Bridge.h"
#include "MenuBuilder.h"
#include "Breakpoints.h"
BreakpointsView::BreakpointsView(QWidget* parent)
: StdTable(parent), mExceptionMaxLength(0)
{
auto charWidth = [this](int count)
{
return getCharWidth() * count + 8;
};
addColumnAt(charWidth(9), tr("Type"), false);
addColumnAt(charWidth(sizeof(duint) * 2), tr("Address"), true);
addColumnAt(charWidth(35), tr("Module/Label/Exception"), true);
addColumnAt(charWidth(8), tr("State"), true);
addColumnAt(charWidth(50), tr("Disassembly"), true);
addColumnAt(charWidth(4), tr("Hits"), true);
addColumnAt(0, tr("Summary"), true);
loadColumnFromConfig("BreakpointsView");
mDisasm = new QBeaEngine(ConfigUint("Disassembler", "MaxModuleSize"));
mDisasm->UpdateConfig();
enableMultiSelection(true);
setupContextMenu();
connect(Bridge::getBridge(), SIGNAL(updateBreakpoints()), this, SLOT(updateBreakpointsSlot()));
connect(Bridge::getBridge(), SIGNAL(disassembleAt(dsint, dsint)), this, SLOT(disassembleAtSlot(dsint, dsint)));
connect(Config(), SIGNAL(tokenizerConfigUpdated()), this, SLOT(tokenizerConfigUpdatedSlot()));
connect(this, SIGNAL(contextMenuSignal(QPoint)), this, SLOT(contextMenuSlot(QPoint)));
connect(this, SIGNAL(doubleClickedSignal()), this, SLOT(followBreakpointSlot()));
connect(this, SIGNAL(enterPressedSignal()), this, SLOT(followBreakpointSlot()));
Initialize();
}
void BreakpointsView::setupContextMenu()
{
mMenuBuilder = new MenuBuilder(this, [this](QMenu*)
{
return DbgIsDebugging();
});
auto validBp = [this](QMenu*)
{
return isValidBp();
};
mMenuBuilder->addAction(makeShortcutAction(DIcon("breakpoint_remove.png"), tr("&Remove"), SLOT(removeBreakpointSlot()), "ActionDeleteBreakpoint"), validBp);
QAction* enableDisableBreakpoint = makeShortcutAction(DIcon("breakpoint_disable.png"), tr("Disable"), SLOT(toggleBreakpointSlot()), "ActionEnableDisableBreakpoint");
mMenuBuilder->addAction(enableDisableBreakpoint, [this, enableDisableBreakpoint](QMenu*)
{
if(!isValidBp())
return false;
if(selectedBp().enabled)
{
enableDisableBreakpoint->setIcon(DIcon("breakpoint_disable.png"));
enableDisableBreakpoint->setText(tr("Disable"));
}
else
{
enableDisableBreakpoint->setIcon(DIcon("breakpoint_enable.png"));
enableDisableBreakpoint->setText(tr("Enable"));
}
return true;
});
mMenuBuilder->addAction(makeShortcutAction(DIcon("breakpoint_edit_alt.png"), tr("&Edit"), SLOT(editBreakpointSlot()), "ActionBinaryEdit"), validBp);
mMenuBuilder->addAction(makeShortcutAction(DIcon("breakpoint_reset_hitcount.png"), tr("Reset hit count"), SLOT(resetHitCountBreakpointSlot()), "ActionResetHitCountBreakpoint"), [this](QMenu*)
{
if(!isValidBp())
return false;
return selectedBp().hitCount > 0;
});
mMenuBuilder->addSeparator();
QAction* enableAll = makeShortcutAction(DIcon("breakpoint_enable_all.png"), QString(), SLOT(enableAllBreakpointsSlot()), "ActionEnableAllBreakpoints");
mMenuBuilder->addAction(enableAll, [this, enableAll](QMenu*)
{
if(!isValidBp())
return false;
enableAll->setText(tr("Enable all (%1)").arg(bpTypeName(selectedBp().type)));
return true;
});
QAction* disableAll = makeShortcutAction(DIcon("breakpoint_disable_all.png"), QString(), SLOT(disableAllBreakpointsSlot()), "ActionDisableAllBreakpoints");
mMenuBuilder->addAction(disableAll, [this, disableAll](QMenu*)
{
if(!isValidBp())
return false;
disableAll->setText(tr("Disable all (%1)").arg(bpTypeName(selectedBp().type)));
return true;
});
QAction* removeAll = makeShortcutAction(DIcon("breakpoint_remove_all.png"), QString(), SLOT(removeAllBreakpointsSlot()), "ActionRemoveAllBreakpoints");
mMenuBuilder->addAction(removeAll, [this, removeAll](QMenu*)
{
if(!isValidBp())
return false;
removeAll->setText(tr("Remove all (%1)").arg(bpTypeName(selectedBp().type)));
return true;
});
mMenuBuilder->addSeparator();
mMenuBuilder->addAction(makeAction(DIcon("breakpoint_module_add.png"), tr("Add DLL breakpoint"), SLOT(addDllBreakpointSlot())));
mMenuBuilder->addAction(makeAction(DIcon("breakpoint_exception_add.png"), tr("Add exception breakpoint"), SLOT(addExceptionBreakpointSlot())));
mMenuBuilder->addSeparator();
MenuBuilder* copyMenu = new MenuBuilder(this);
setupCopyMenu(copyMenu);
mMenuBuilder->addMenu(makeMenu(DIcon("copy.png"), tr("&Copy")), copyMenu);
}
void BreakpointsView::updateColors()
{
StdTable::updateColors();
mDisasmBackgroundColor = ConfigColor("DisassemblyBackgroundColor");
mDisasmSelectionColor = ConfigColor("DisassemblySelectionColor");
mCipBackgroundColor = ConfigColor("ThreadCurrentBackgroundColor");
mCipColor = ConfigColor("ThreadCurrentColor");
mSummaryParenColor = ConfigColor("BreakpointSummaryParenColor");
mSummaryKeywordColor = ConfigColor("BreakpointSummaryKeywordColor");
mSummaryStringColor = ConfigColor("BreakpointSummaryStringColor");
mDisasm->UpdateConfig();
updateBreakpointsSlot();
}
void BreakpointsView::sortRows(int column, bool ascending)
{
std::stable_sort(mData.begin(), mData.end(), [this, column, ascending](const std::vector<CellData> & a, const std::vector<CellData> & b)
{
//this function sorts on header type first and then on column content
auto aBp = &mBps.at(a.at(ColAddr).userdata), bBp = &mBps.at(b.at(ColAddr).userdata);
auto aType = aBp->type, bType = bBp->type;
auto aHeader = aBp->addr || aBp->active, bHeader = bBp->addr || bBp->active;
struct Hax
{
const bool & greater;
const QString & s;
Hax(const bool & greater, const QString & s) : greater(greater), s(s) { }
bool operator<(const Hax & b)
{
return greater ? s > b.s : s < b.s;
}
} aHax(!ascending, a.at(column).text), bHax(!ascending, b.at(column).text);
return std::tie(aType, aHeader, aHax) < std::tie(bType, bHeader, bHax);
});
}
QString BreakpointsView::paintContent(QPainter* painter, dsint rowBase, int rowOffset, int col, int x, int y, int w, int h)
{
if(isSelected(rowBase, rowOffset))
painter->fillRect(QRect(x, y, w, h), QBrush(col == ColDisasm ? mDisasmSelectionColor : mSelectionColor));
else if(col == ColDisasm)
painter->fillRect(QRect(x, y, w, h), QBrush(mDisasmBackgroundColor));
auto index = bpIndex(rowBase + rowOffset);
auto & bp = mBps.at(index);
auto cellContent = getCellContent(rowBase + rowOffset, col);
if(col > ColType && !bp.addr && !bp.active)
{
auto mid = h / 2.0;
painter->drawLine(QPointF(x, y + mid), QPointF(x + w, y + mid));
}
else if(col == ColAddr)
{
if(bp.type == bp_dll || bp.type == bp_exception)
return cellContent;
else if(bp.addr && bp.addr == mCip)
{
painter->fillRect(QRect(x, y, w, h), QBrush(mCipBackgroundColor));
painter->setPen(QPen(mCipColor));
painter->drawText(QRect(x + 4, y, w - 4, h), Qt::AlignVCenter | Qt::AlignLeft, cellContent);
return QString();
}
}
else if(col == ColDisasm)
{
RichTextPainter::paintRichText(painter, x + 4, y, w - 4, h, 0, mRich.at(index).first, mFontMetrics);
return QString();
}
else if(col == ColSummary)
{
RichTextPainter::paintRichText(painter, x + 4, y, w - 4, h, 0, mRich.at(index).second, mFontMetrics);
return QString();
}
return cellContent;
}
void BreakpointsView::updateBreakpointsSlot()
{
if(mExceptionMap.empty() && DbgFunctions()->EnumExceptions)
{
BridgeList<CONSTANTINFO> exceptions;
DbgFunctions()->EnumExceptions(&exceptions);
for(int i = 0; i < exceptions.Count(); i++)
{
mExceptionMap.insert({exceptions[i].value, exceptions[i].name});
mExceptionList.append(QString(exceptions[i].name));
mExceptionMaxLength = std::max(mExceptionMaxLength, int(strlen(exceptions[i].name)));
}
mExceptionList.sort();
}
BPMAP bpmap;
DbgGetBpList(bp_none, &bpmap);
setRowCount(bpmap.count);
mBps.clear();
mBps.reserve(bpmap.count + 5);
mRich.clear();
mRich.reserve(bpmap.count + 5);
BPXTYPE lasttype = bp_none;
for(int i = 0, row = 0; i < bpmap.count; i++, row++)
{
BRIDGEBP & bp = bpmap.bp[i];
if(lasttype != bp.type)
{
lasttype = bp.type;
setRowCount(getRowCount() + 1);
setCellContent(row, ColType, bpTypeName(bp.type));
setCellUserdata(row, ColType, bp.type);
setCellContent(row, ColHits, QString());
setCellContent(row, ColAddr, QString());
setCellUserdata(row, ColAddr, row);
setCellContent(row, ColModLabel, QString());
setCellContent(row, ColState, QString());
setCellContent(row, ColDisasm, QString());
setCellContent(row, ColSummary, QString());
row++;
BRIDGEBP fakebp;
memset(&fakebp, 0, sizeof(fakebp));
fakebp.type = lasttype;
mBps.push_back(fakebp);
mRich.push_back(std::make_pair(RichTextPainter::List(), RichTextPainter::List()));
}
mBps.push_back(bp);
RichTextPainter::List richSummary, richDisasm;
auto addrText = [&]()
{
if(bp.type == bp_dll)
{
auto base = DbgModBaseFromName(bp.mod);
if(!base)
base = -1;
return ToPtrString(base);
}
else
return ToPtrString(bp.addr);
};
auto modLabelText = [&]() -> QString
{
char label[MAX_LABEL_SIZE] = "";
if(bp.type == bp_exception)
{
auto found = mExceptionMap.find(bp.addr);
return found == mExceptionMap.end() ? "" : found->second;
}
else if(bp.type != bp_dll && DbgGetLabelAt(bp.addr, SEG_DEFAULT, label))
return QString("<%1.%2>").arg(bp.mod, label);
else
return bp.mod;
};
auto stateName = [&]()
{
if(!bp.active)
return tr("Inactive");
if(bp.enabled)
return bp.singleshoot ? tr("One-time") : tr("Enabled");
else
return tr("Disabled");
};
auto disasmText = [&]() -> QString
{
QString result;
if(!bp.active || bp.type == bp_dll || bp.type == bp_exception)
return result;
byte_t data[MAX_DISASM_BUFFER];
if(DbgMemRead(bp.addr, data, sizeof(data)))
{
auto instr = mDisasm->DisassembleAt(data, sizeof(data), 0, bp.addr);
ZydisTokenizer::TokenToRichText(instr.tokens, richDisasm, 0);
for(auto & token : richDisasm)
result += token.text;
}
return result;
};
//memory/hardware/dll/exception type, name, address comment, condition, log(text+condition), command(text+condition)
auto summaryText = [&]()
{
auto colored = [&richSummary](QString text, QColor color)
{
RichTextPainter::CustomRichText_t token;
token.highlight = false;
token.flags = RichTextPainter::FlagColor;
token.textColor = color;
token.text = text;
richSummary.push_back(token);
};
auto text = [this, &richSummary](QString text)
{
RichTextPainter::CustomRichText_t token;
token.highlight = false;
token.flags = RichTextPainter::FlagColor;
token.textColor = this->mTextColor;
token.text = text;
richSummary.push_back(token);
};
auto next = [&richSummary, &text]()
{
if(!richSummary.empty())
text(", ");
};
char comment[MAX_COMMENT_SIZE];
if(bp.type != bp_dll && bp.type != bp_exception && DbgGetCommentAt(bp.addr, comment) && *comment != '\1')
{
next();
colored(comment, mSummaryStringColor);
}
else if(*bp.name)
{
next();
colored(bp.name, mSummaryStringColor);
}
switch(bp.type)
{
case bp_normal:
break;
case bp_hardware:
{
auto size = [](BPHWSIZE size)
{
switch(size)
{
case hw_byte:
return tr("byte");
case hw_word:
return tr("word");
case hw_dword:
return tr("dword");
case hw_qword:
return tr("qword");
default:
return QString();
}
}(BPHWSIZE(bp.hwSize));
switch(bp.typeEx)
{
case hw_access:
next();
colored(tr("access"), mSummaryKeywordColor);
colored("(", mSummaryParenColor);
text(size);
colored(")", mSummaryParenColor);
break;
case hw_write:
next();
colored(tr("write"), mSummaryKeywordColor);
colored("(", mSummaryParenColor);
text(size);
colored(")", mSummaryParenColor);
break;
case hw_execute:
next();
colored(tr("execute"), mSummaryKeywordColor);
colored("()", mSummaryParenColor);
break;
}
}
break;
case bp_memory:
{
auto op = [](BPMEMTYPE type)
{
switch(type)
{
case mem_access:
return tr("access");
case mem_read:
return tr("read");
case mem_write:
return tr("write");
case mem_execute:
return tr("execute");
default:
return QString();
}
}(BPMEMTYPE(bp.typeEx));
next();
colored(op, mSummaryKeywordColor);
colored("(", mSummaryParenColor);
text(ToHexString(DbgFunctions()->MemBpSize(bp.addr)));
colored(")", mSummaryParenColor);
}
break;
case bp_dll:
switch(bp.typeEx)
{
case dll_load:
next();
colored(tr("load"), mSummaryKeywordColor);
colored("()", mSummaryParenColor);
break;
case dll_unload:
next();
colored(tr("unload"), mSummaryKeywordColor);
colored("()", mSummaryParenColor);
break;
case dll_all:
next();
colored(tr("all"), mSummaryKeywordColor);
colored("()", mSummaryParenColor);
break;
}
break;
case bp_exception:
switch(bp.typeEx)
{
case ex_firstchance:
next();
colored(tr("firstchance"), mSummaryKeywordColor);
colored("()", mSummaryParenColor);
break;
case ex_secondchance:
next();
colored(tr("secondchance"), mSummaryKeywordColor);
colored("()", mSummaryParenColor);
break;
case ex_all:
next();
colored(tr("anychance"), mSummaryKeywordColor);
colored("()", mSummaryParenColor);
break;
}
break;
default:
return QString();
}
if(*bp.breakCondition)
{
next();
colored("breakif", mSummaryKeywordColor);
colored("(", mSummaryParenColor);
text(bp.breakCondition);
colored(")", mSummaryParenColor);
}
if(bp.fastResume)
{
next();
colored(tr("fastresume"), mSummaryKeywordColor);
colored("()", mSummaryParenColor);
}
else //fast resume skips all other steps
{
if(*bp.logText)
{
next();
colored(tr("log"), mSummaryKeywordColor);
if(*bp.logCondition)
{
colored("if", mSummaryKeywordColor);
colored("(", mSummaryParenColor);
text(bp.logCondition);
colored(",", mSummaryParenColor);
text(" ");
}
else
colored("(", mSummaryParenColor);
colored(QString("\"%1\"").arg(bp.logText), mSummaryStringColor);
colored(")", mSummaryParenColor);
}
if(*bp.commandText)
{
next();
colored(tr("cmd"), mSummaryKeywordColor);
if(*bp.commandCondition)
{
colored("if", mSummaryKeywordColor);
colored("(", mSummaryParenColor);
text(bp.commandCondition);
colored(",", mSummaryParenColor);
text(" ");
}
else
colored("(", mSummaryParenColor);
colored(QString("\"%1\"").arg(bp.commandText), mSummaryStringColor);
colored(")", mSummaryParenColor);
}
}
QString result;
for(auto & token : richSummary)
result += token.text;
return result;
};
setCellContent(row, ColType, QString());
setCellUserdata(row, ColType, bp.type);
setCellContent(row, ColAddr, addrText());
setCellUserdata(row, ColAddr, row);
setCellContent(row, ColModLabel, modLabelText());
setCellContent(row, ColState, stateName());
setCellContent(row, ColDisasm, disasmText());
setCellContent(row, ColHits, QString("%1").arg(bp.hitCount));
setCellContent(row, ColSummary, summaryText());
mRich.push_back(std::make_pair(std::move(richDisasm), std::move(richSummary)));
}
if(bpmap.count)
{
BridgeFree(bpmap.bp);
auto sel = getInitialSelection();
auto rows = getRowCount();
if(sel >= rows)
setSingleSelection(rows - 1);
}
reloadData();
}
void BreakpointsView::disassembleAtSlot(dsint addr, dsint cip)
{
Q_UNUSED(addr);
mCip = cip;
}
void BreakpointsView::tokenizerConfigUpdatedSlot()
{
mDisasm->UpdateConfig();
updateBreakpointsSlot();
}
void BreakpointsView::contextMenuSlot(const QPoint & pos)
{
QMenu wMenu(this);
mMenuBuilder->build(&wMenu);
if(!wMenu.actions().isEmpty())
wMenu.exec(mapToGlobal(pos));
}
void BreakpointsView::followBreakpointSlot()
{
if(!isValidBp())
return;
auto & bp = selectedBp();
if(bp.type == bp_exception || !bp.active)
return;
duint addr = bp.type == bp_dll ? DbgModBaseFromName(bp.mod) : bp.addr;
if(!DbgMemIsValidReadPtr(addr))
return;
if(DbgFunctions()->MemIsCodePage(addr, false))
DbgCmdExecDirect(QString("disasm %1").arg(ToPtrString(addr)));
else
{
DbgCmdExecDirect(QString("dump %1").arg(ToPtrString(addr)));
emit Bridge::getBridge()->getDumpAttention();
}
}
void BreakpointsView::removeBreakpointSlot()
{
for(int i : getSelection())
{
if(isValidBp(i))
{
const BRIDGEBP & bp = selectedBp(i);
if(bp.active)
Breakpoints::removeBP(bp);
else
DbgCmdExec(QString().sprintf("bc \"%s\":$%X", bp.mod, bp.addr));
}
}
}
void BreakpointsView::toggleBreakpointSlot()
{
for(int i : getSelection())
if(isValidBp(i))
Breakpoints::toggleBPByDisabling(selectedBp(i));
}
void BreakpointsView::editBreakpointSlot()
{
if(!isValidBp())
return;
const BRIDGEBP & bp = selectedBp();
if(bp.type == bp_dll)
{
Breakpoints::editBP(bp_dll, bp.mod, this);
}
else if(bp.active || bp.type == bp_exception)
{
Breakpoints::editBP(bp.type, ToPtrString(bp.addr), this);
}
else
{
QString addrText = QString().sprintf("\"%s\":$%X", bp.mod, bp.addr);
EditBreakpointDialog dialog(this, bp);
if(dialog.exec() != QDialog::Accepted)
return;
auto exec = [](const QString & command)
{
DbgCmdExecDirect(command.toUtf8().constData());
};
const BRIDGEBP & newBp = dialog.getBp();
switch(bp.type)
{
case bp_normal:
exec(QString("SetBreakpointName %1, \"%2\"").arg(addrText).arg(newBp.name));
exec(QString("SetBreakpointCondition %1, \"%2\"").arg(addrText).arg(newBp.breakCondition));
exec(QString("SetBreakpointLog %1, \"%2\"").arg(addrText).arg(newBp.logText));
exec(QString("SetBreakpointLogCondition %1, \"%2\"").arg(addrText).arg(newBp.logCondition));
exec(QString("SetBreakpointCommand %1, \"%2\"").arg(addrText).arg(newBp.commandText));
exec(QString("SetBreakpointCommandCondition %1, \"%2\"").arg(addrText).arg(newBp.commandCondition));
exec(QString("ResetBreakpointHitCount %1, %2").arg(addrText).arg(ToPtrString(newBp.hitCount)));
exec(QString("SetBreakpointFastResume %1, %2").arg(addrText).arg(newBp.fastResume));
exec(QString("SetBreakpointSilent %1, %2").arg(addrText).arg(newBp.silent));
exec(QString("SetBreakpointSingleshoot %1, %2").arg(addrText).arg(newBp.singleshoot));
break;
case bp_hardware:
exec(QString("SetHardwareBreakpointName %1, \"%2\"").arg(addrText).arg(newBp.name));
exec(QString("SetHardwareBreakpointCondition %1, \"%2\"").arg(addrText).arg(newBp.breakCondition));
exec(QString("SetHardwareBreakpointLog %1, \"%2\"").arg(addrText).arg(newBp.logText));
exec(QString("SetHardwareBreakpointLogCondition %1, \"%2\"").arg(addrText).arg(newBp.logCondition));
exec(QString("SetHardwareBreakpointCommand %1, \"%2\"").arg(addrText).arg(newBp.commandText));
exec(QString("SetHardwareBreakpointCommandCondition %1, \"%2\"").arg(addrText).arg(newBp.commandCondition));
exec(QString("ResetHardwareBreakpointHitCount %1, %2").arg(addrText).arg(ToPtrString(newBp.hitCount)));
exec(QString("SetHardwareBreakpointFastResume %1, %2").arg(addrText).arg(newBp.fastResume));
exec(QString("SetHardwareBreakpointSilent %1, %2").arg(addrText).arg(newBp.silent));
exec(QString("SetHardwareBreakpointSingleshoot %1, %2").arg(addrText).arg(newBp.singleshoot));
break;
case bp_memory:
exec(QString("SetMemoryBreakpointName %1, \"\"%2\"\"").arg(addrText).arg(newBp.name));
exec(QString("SetMemoryBreakpointCondition %1, \"%2\"").arg(addrText).arg(newBp.breakCondition));
exec(QString("SetMemoryBreakpointLog %1, \"%2\"").arg(addrText).arg(newBp.logText));
exec(QString("SetMemoryBreakpointLogCondition %1, \"%2\"").arg(addrText).arg(newBp.logCondition));
exec(QString("SetMemoryBreakpointCommand %1, \"%2\"").arg(addrText).arg(newBp.commandText));
exec(QString("SetMemoryBreakpointCommandCondition %1, \"%2\"").arg(addrText).arg(newBp.commandCondition));
exec(QString("ResetMemoryBreakpointHitCount %1, %2").arg(addrText).arg(ToPtrString(newBp.hitCount)));
exec(QString("SetMemoryBreakpointFastResume %1, %2").arg(addrText).arg(newBp.fastResume));
exec(QString("SetMemoryBreakpointSilent %1, %2").arg(addrText).arg(newBp.silent));
exec(QString("SetMemoryBreakpointSingleshoot %1, %2").arg(addrText).arg(newBp.singleshoot));
break;
default:
break;
}
}
}
void BreakpointsView::resetHitCountBreakpointSlot()
{
for(int i : getSelection())
{
if(!isValidBp(i))
continue;
auto & bp = selectedBp(i);
DbgCmdExec([&bp]()
{
switch(bp.type)
{
case bp_normal:
return QString("ResetBreakpointHitCount %1").arg(ToPtrString(bp.addr));
case bp_hardware:
return QString("ResetHardwareBreakpointHitCount %1").arg(ToPtrString(bp.addr));
case bp_memory:
return QString("ResetMemoryBreakpointHitCount %1").arg(ToPtrString(bp.addr));
case bp_dll:
return QString("ResetLibrarianBreakpointHitCount \"%1\"").arg(bp.mod);
case bp_exception:
return QString("ResetExceptionBreakpointHitCount %1").arg(ToHexString(bp.addr));
default:
return QString("invalid");
}
}());
QString cmd;
DbgCmdExec(cmd);
}
}
void BreakpointsView::enableAllBreakpointsSlot()
{
if(mBps.empty())
return;
DbgCmdExec([this]()
{
switch(selectedBp().type)
{
case bp_normal:
return "bpe";
case bp_hardware:
return "bphwe";
case bp_memory:
return "bpme";
case bp_dll:
return "bpdll";
case bp_exception:
return "EnableExceptionBPX";
default:
return "invalid";
}
}());
}
void BreakpointsView::disableAllBreakpointsSlot()
{
if(mBps.empty())
return;
DbgCmdExec([this]()
{
switch(selectedBp().type)
{
case bp_normal:
return "bpd";
case bp_hardware:
return "bphwd";
case bp_memory:
return "bpmd";
case bp_dll:
return "bpddll";
case bp_exception:
return "DisableExceptionBPX";
default:
return "invalid";
}
}());
}
void BreakpointsView::removeAllBreakpointsSlot()
{
if(mBps.empty())
return;
DbgCmdExec([this]()
{
switch(selectedBp().type)
{
case bp_normal:
return "bc";
case bp_hardware:
return "bphwc";
case bp_memory:
return "bpmc";
case bp_dll:
return "bcdll";
case bp_exception:
return "DeleteExceptionBPX";
default:
return "invalid";
}
}());
}
void BreakpointsView::addDllBreakpointSlot()
{
QString fileName;
if(SimpleInputBox(this, tr("Enter the module name"), "", fileName, tr("Example: mydll.dll"), &DIcon("breakpoint.png")) && !fileName.isEmpty())
DbgCmdExec(QString("bpdll \"%1\"").arg(fileName));
}
void BreakpointsView::addExceptionBreakpointSlot()
{
QString exception;
if(SimpleChoiceBox(this, tr("Enter the exception code"), "", mExceptionList, exception, true, tr("Example: EXCEPTION_ACCESS_VIOLATION"), &DIcon("breakpoint.png"), mExceptionMaxLength) && !exception.isEmpty())
DbgCmdExec((QString("SetExceptionBPX ") + exception));
}