From 29205263b5fc9b2d64d964cbb689665fd2dce502 Mon Sep 17 00:00:00 2001 From: Matthijs Lavrijsen Date: Fri, 29 Jan 2021 11:32:20 +0100 Subject: [PATCH 1/3] GUI: update exceptions tab in preferences view - Add per-exception(-range) settings to determine if and when to break, whether to log and whether the exception should be passed to the debuggee - Add 'unknown exceptions' item to the exception filters list --- src/gui/Src/Gui/SettingsDialog.cpp | 223 ++++++++++++++++++++++++----- src/gui/Src/Gui/SettingsDialog.h | 49 +++++-- src/gui/Src/Gui/SettingsDialog.ui | 91 ++++++++++-- 3 files changed, 312 insertions(+), 51 deletions(-) diff --git a/src/gui/Src/Gui/SettingsDialog.cpp b/src/gui/Src/Gui/SettingsDialog.cpp index 3db45a01..6cb133c1 100644 --- a/src/gui/Src/Gui/SettingsDialog.cpp +++ b/src/gui/Src/Gui/SettingsDialog.cpp @@ -70,7 +70,7 @@ void SettingsDialog::LoadSettings() settings.engineAnimateInterval = 50; settings.engineHardcoreThreadSwitchWarning = false; settings.engineVerboseExceptionLogging = true; - settings.exceptionRanges = &realExceptionRanges; + settings.exceptionFilters = &realExceptionFilters; settings.disasmArgumentSpaces = false; settings.disasmHidePointerSizes = false; settings.disasmHideNormalSegments = false; @@ -210,22 +210,51 @@ void SettingsDialog::LoadSettings() //Exceptions tab char exceptionRange[MAX_SETTING_SIZE] = ""; + bool unknownExceptionsFilterAdded = false; if(BridgeSettingGet("Exceptions", "IgnoreRange", exceptionRange)) { QStringList ranges = QString(exceptionRange).split(QString(","), QString::SkipEmptyParts); for(int i = 0; i < ranges.size(); i++) { + const QString & entry = ranges.at(i); unsigned long start; unsigned long end; - if(sscanf_s(ranges.at(i).toUtf8().constData(), "%08X-%08X", &start, &end) == 2 && start <= end) + if(!entry.contains("debug") && // check for old ignore format + sscanf_s(entry.toUtf8().constData(), "%08X-%08X", &start, &end) == 2 && start <= end) { - RangeStruct newRange; - newRange.start = start; - newRange.end = end; - AddRangeToList(newRange); + ExceptionFilter newFilter; + newFilter.range.start = start; + newFilter.range.end = end; + // Default settings for an ignore entry + newFilter.breakOn = ExceptionBreakOn::SecondChance; + newFilter.logException = true; + newFilter.handledBy = ExceptionHandledBy::Debuggee; + AddExceptionFilterToList(newFilter); + } + else if(entry.contains("debug") && // new filter format + sscanf_s(entry.toUtf8().constData(), "%08X-%08X", &start, &end) == 2 && start <= end) + { + ExceptionFilter newFilter; + newFilter.range.start = start; + newFilter.range.end = end; + newFilter.breakOn = entry.contains("first") ? ExceptionBreakOn::FirstChance : entry.contains("second") ? ExceptionBreakOn::SecondChance : ExceptionBreakOn::DoNotBreak; + newFilter.logException = !entry.contains("nolog"); + newFilter.handledBy = entry.contains("debugger") ? ExceptionHandledBy::Debugger : ExceptionHandledBy::Debuggee; + AddExceptionFilterToList(newFilter); + if(newFilter.range.start == 0 && newFilter.range.start == newFilter.range.end) + unknownExceptionsFilterAdded = true; } } } + if(!unknownExceptionsFilterAdded) // add a default filter for unknown exceptions if it was not yet present in settings + { + ExceptionFilter unknownExceptionsFilter; + unknownExceptionsFilter.range.start = unknownExceptionsFilter.range.end = 0; + unknownExceptionsFilter.breakOn = ExceptionBreakOn::FirstChance; + unknownExceptionsFilter.logException = true; + unknownExceptionsFilter.handledBy = ExceptionHandledBy::Debuggee; + AddExceptionFilterToList(unknownExceptionsFilter); + } //Disasm tab GetSettingBool("Disassembler", "ArgumentSpaces", &settings.disasmArgumentSpaces); @@ -396,8 +425,15 @@ void SettingsDialog::SaveSettings() //Exceptions tab QString exceptionRange = ""; - for(int i = 0; i < settings.exceptionRanges->size(); i++) - exceptionRange.append(QString().sprintf("%.8X-%.8X", settings.exceptionRanges->at(i).start, settings.exceptionRanges->at(i).end) + QString(",")); + for(int i = 0; i < settings.exceptionFilters->size(); i++) + { + const ExceptionFilter & filter = settings.exceptionFilters->at(i); + exceptionRange.append(QString().asprintf("%.8X-%.8X:%s:%s:%s,", + filter.range.start, filter.range.end, + (filter.breakOn == ExceptionBreakOn::FirstChance ? "first" : filter.breakOn == ExceptionBreakOn::SecondChance ? "second" : "nobreak"), + (filter.logException ? "log" : "nolog"), + (filter.handledBy == ExceptionHandledBy::Debugger ? "debugger" : "debuggee"))); + } exceptionRange.chop(1); //remove last comma if(exceptionRange.size()) BridgeSettingSet("Exceptions", "IgnoreRange", exceptionRange.toUtf8().constData()); @@ -485,32 +521,102 @@ void SettingsDialog::SaveSettings() GuiUpdateAllViews(); } -void SettingsDialog::AddRangeToList(RangeStruct range) +void SettingsDialog::AddExceptionFilterToList(ExceptionFilter filter) { //check range - unsigned long start = range.start; - unsigned long end = range.end; + unsigned long start = filter.range.start; + unsigned long end = filter.range.end; - for(int i = settings.exceptionRanges->size() - 1; i > -1; i--) + for(int i = settings.exceptionFilters->size() - 1; i > -1; i--) { - unsigned long curStart = settings.exceptionRanges->at(i).start; - unsigned long curEnd = settings.exceptionRanges->at(i).end; + unsigned long curStart = settings.exceptionFilters->at(i).range.start; + unsigned long curEnd = settings.exceptionFilters->at(i).range.end; if(curStart <= end && curEnd >= start) //ranges overlap { if(curStart < start) //extend range to the left start = curStart; if(curEnd > end) //extend range to the right end = curEnd; - settings.exceptionRanges->erase(settings.exceptionRanges->begin() + i); //remove old range + settings.exceptionFilters->erase(settings.exceptionFilters->begin() + i); //remove old range } } - range.start = start; - range.end = end; - settings.exceptionRanges->push_back(range); - qSort(settings.exceptionRanges->begin(), settings.exceptionRanges->end(), RangeStructLess()); + filter.range.start = start; + filter.range.end = end; + settings.exceptionFilters->push_back(filter); + UpdateExceptionListWidget(); +} + +void SettingsDialog::OnExceptionFilterSelectionChanged(QListWidgetItem* selected) +{ + QModelIndexList indexes = ui->listExceptions->selectionModel()->selectedIndexes(); + if(!indexes.size() && !selected) // no selection + return; + int row; + if(!indexes.size()) + row = ui->listExceptions->row(selected); + else + row = indexes.at(0).row(); + if(row < 0 || row >= settings.exceptionFilters->count()) + return; + + const ExceptionFilter & filter = settings.exceptionFilters->at(row); + if(filter.breakOn == ExceptionBreakOn::FirstChance) + ui->radioFirstChance->setChecked(true); + else if(filter.breakOn == ExceptionBreakOn::SecondChance) + ui->radioSecondChance->setChecked(true); + else + ui->radioDoNotBreak->setChecked(true); + if(filter.handledBy == ExceptionHandledBy::Debugger) + ui->radioHandledByDebugger->setChecked(true); + else + ui->radioHandledByDebuggee->setChecked(true); + ui->chkLogException->setChecked(filter.logException); + + if(filter.range.start == 0 && filter.range.start == filter.range.end) // disallow deleting the 'unknown exceptions' filter + ui->btnDeleteRange->setEnabled(false); + else + ui->btnDeleteRange->setEnabled(true); +} + +void SettingsDialog::OnCurrentExceptionFilterSettingsChanged() +{ + QModelIndexList indexes = ui->listExceptions->selectionModel()->selectedIndexes(); + if(!indexes.size()) // no selection + return; + int row = indexes.at(0).row(); + if(row < 0 || row >= settings.exceptionFilters->count()) + return; + + ExceptionFilter filter = settings.exceptionFilters->at(row); + if(ui->radioFirstChance->isChecked()) + filter.breakOn = ExceptionBreakOn::FirstChance; + else if(ui->radioSecondChance->isChecked()) + filter.breakOn = ExceptionBreakOn::SecondChance; + else + filter.breakOn = ExceptionBreakOn::DoNotBreak; + filter.logException = ui->chkLogException->isChecked(); + if(ui->radioHandledByDebugger->isChecked()) + filter.handledBy = ExceptionHandledBy::Debugger; + else + filter.handledBy = ExceptionHandledBy::Debuggee; + + settings.exceptionFilters->erase(settings.exceptionFilters->begin() + row); + settings.exceptionFilters->push_back(filter); + qSort(settings.exceptionFilters->begin(), settings.exceptionFilters->end(), ExceptionFilterLess()); +} + +void SettingsDialog::UpdateExceptionListWidget() +{ + qSort(settings.exceptionFilters->begin(), settings.exceptionFilters->end(), ExceptionFilterLess()); ui->listExceptions->clear(); - for(int i = 0; i < settings.exceptionRanges->size(); i++) - ui->listExceptions->addItem(QString().sprintf("%.8X-%.8X", settings.exceptionRanges->at(i).start, settings.exceptionRanges->at(i).end)); + for(int i = 0; i < settings.exceptionFilters->size(); i++) + { + const ExceptionFilter & filter = settings.exceptionFilters->at(i); + if(filter.range.start == 0 && filter.range.start == filter.range.end) + ui->listExceptions->addItem(QString("Unknown exceptions")); + else + ui->listExceptions->addItem(QString().asprintf("%.8X-%.8X", filter.range.start, filter.range.end)); + } } void SettingsDialog::setLastException(unsigned int exceptionCode) @@ -724,15 +830,19 @@ void SettingsDialog::on_chkTraceRecordEnabledDuringTrace_stateChanged(int arg1) settings.engineEnableTraceRecordDuringTrace = arg1 == Qt::Checked; } -void SettingsDialog::on_btnAddRange_clicked() +void SettingsDialog::on_btnIgnoreRange_clicked() { ExceptionRangeDialog exceptionRange(this); if(exceptionRange.exec() != QDialog::Accepted) return; - RangeStruct range; - range.start = exceptionRange.rangeStart; - range.end = exceptionRange.rangeEnd; - AddRangeToList(range); + + ExceptionFilter filter; + filter.range.start = exceptionRange.rangeStart; + filter.range.end = exceptionRange.rangeEnd; + filter.breakOn = ExceptionBreakOn::SecondChance; + filter.logException = true; + filter.handledBy = ExceptionHandledBy::Debuggee; + AddExceptionFilterToList(filter); } void SettingsDialog::on_btnDeleteRange_clicked() @@ -740,13 +850,12 @@ void SettingsDialog::on_btnDeleteRange_clicked() QModelIndexList indexes = ui->listExceptions->selectionModel()->selectedIndexes(); if(!indexes.size()) //no selection return; - settings.exceptionRanges->erase(settings.exceptionRanges->begin() + indexes.at(0).row()); - ui->listExceptions->clear(); - for(int i = 0; i < settings.exceptionRanges->size(); i++) - ui->listExceptions->addItem(QString().sprintf("%.8X-%.8X", settings.exceptionRanges->at(i).start, settings.exceptionRanges->at(i).end)); + + settings.exceptionFilters->erase(settings.exceptionFilters->begin() + indexes.at(0).row()); + UpdateExceptionListWidget(); } -void SettingsDialog::on_btnAddLast_clicked() +void SettingsDialog::on_btnIgnoreLast_clicked() { QMessageBox msg(QMessageBox::Question, tr("Question"), QString().sprintf(tr("Are you sure you want to add %.8X?").toUtf8().constData(), lastException)); msg.setWindowIcon(DIcon("question.png")); @@ -756,10 +865,54 @@ void SettingsDialog::on_btnAddLast_clicked() msg.setDefaultButton(QMessageBox::Yes); if(msg.exec() != QMessageBox::Yes) return; - RangeStruct range; - range.start = lastException; - range.end = lastException; - AddRangeToList(range); + + ExceptionFilter filter; + filter.range.start = lastException; + filter.range.end = lastException; + filter.breakOn = ExceptionBreakOn::SecondChance; + filter.logException = true; + filter.handledBy = ExceptionHandledBy::Debuggee; + AddExceptionFilterToList(filter); +} + +void SettingsDialog::on_listExceptions_currentItemChanged(QListWidgetItem* current, QListWidgetItem*) +{ + OnExceptionFilterSelectionChanged(current); +} + +void SettingsDialog::on_listExceptions_itemClicked(QListWidgetItem* item) +{ + OnExceptionFilterSelectionChanged(item); +} + +void SettingsDialog::on_radioFirstChance_clicked() +{ + OnCurrentExceptionFilterSettingsChanged(); +} + +void SettingsDialog::on_radioSecondChance_clicked() +{ + OnCurrentExceptionFilterSettingsChanged(); +} + +void SettingsDialog::on_radioDoNotBreak_clicked() +{ + OnCurrentExceptionFilterSettingsChanged(); +} + +void SettingsDialog::on_chkLogException_stateChanged(int arg1) +{ + OnCurrentExceptionFilterSettingsChanged(); +} + +void SettingsDialog::on_radioHandledByDebugger_clicked() +{ + OnCurrentExceptionFilterSettingsChanged(); +} + +void SettingsDialog::on_radioHandledByDebuggee_clicked() +{ + OnCurrentExceptionFilterSettingsChanged(); } void SettingsDialog::on_chkArgumentSpaces_stateChanged(int arg1) diff --git a/src/gui/Src/Gui/SettingsDialog.h b/src/gui/Src/Gui/SettingsDialog.h index 9550f2ad..8f20261b 100644 --- a/src/gui/Src/Gui/SettingsDialog.h +++ b/src/gui/Src/Gui/SettingsDialog.h @@ -2,6 +2,7 @@ #define SETTINGSDIALOG_H #include +#include #include "Imports.h" namespace Ui @@ -66,9 +67,17 @@ private slots: void on_spinMaxTraceCount_valueChanged(int arg1); void on_spinAnimateInterval_valueChanged(int arg1); //Exception tab - void on_btnAddRange_clicked(); + void on_btnIgnoreRange_clicked(); void on_btnDeleteRange_clicked(); - void on_btnAddLast_clicked(); + void on_btnIgnoreLast_clicked(); + void on_listExceptions_currentItemChanged(QListWidgetItem* current, QListWidgetItem* previous); + void on_listExceptions_itemClicked(QListWidgetItem* item); + void on_radioFirstChance_clicked(); + void on_radioSecondChance_clicked(); + void on_radioDoNotBreak_clicked(); + void on_chkLogException_stateChanged(int arg1); + void on_radioHandledByDebugger_clicked(); + void on_radioHandledByDebuggee_clicked(); //Disasm tab void on_chkArgumentSpaces_stateChanged(int arg1); void on_chkHidePointerSizes_stateChanged(int arg1); @@ -123,6 +132,19 @@ private: break_ud2 = 2 }; + enum class ExceptionBreakOn + { + FirstChance, + SecondChance, + DoNotBreak + }; + + enum class ExceptionHandledBy + { + Debugger, + Debuggee + }; + //structures struct RangeStruct { @@ -130,11 +152,19 @@ private: unsigned long end; }; - struct RangeStructLess + struct ExceptionFilter { - bool operator()(const RangeStruct a, const RangeStruct b) const + RangeStruct range; + ExceptionBreakOn breakOn; + bool logException; + ExceptionHandledBy handledBy; + }; + + struct ExceptionFilterLess + { + bool operator()(const ExceptionFilter a, const ExceptionFilter b) const { - return a.start < b.start; + return a.range.start < b.range.start; } }; @@ -175,7 +205,7 @@ private: int engineMaxTraceCount; int engineAnimateInterval; //Exception Tab - QList* exceptionRanges; + QList* exceptionFilters; //Disasm Tab bool disasmArgumentSpaces; bool disasmMemorySpaces; @@ -219,7 +249,7 @@ private: //variables Ui::SettingsDialog* ui; SettingsStruct settings; - QList realExceptionRanges; + QList realExceptionFilters; bool bJitOld; bool bJitAutoOld; bool bGuiOptionsUpdated; @@ -230,7 +260,10 @@ private: void GetSettingBool(const char* section, const char* name, bool* set); Qt::CheckState bool2check(bool checked); void LoadSettings(); - void AddRangeToList(RangeStruct range); + void AddExceptionFilterToList(ExceptionFilter filter); + void OnExceptionFilterSelectionChanged(QListWidgetItem* selected); + void OnCurrentExceptionFilterSettingsChanged(); + void UpdateExceptionListWidget(); }; #endif // SETTINGSDIALOG_H diff --git a/src/gui/Src/Gui/SettingsDialog.ui b/src/gui/Src/Gui/SettingsDialog.ui index c3822dbc..daa0626e 100644 --- a/src/gui/Src/Gui/SettingsDialog.ui +++ b/src/gui/Src/Gui/SettingsDialog.ui @@ -466,9 +466,9 @@ - + - Ignored Exceptions: + Exception Filters: @@ -503,9 +503,9 @@ - + - Add &Range + Ignore &Range @@ -517,12 +517,87 @@ - + - Add &Last + Ignore &Last + + + + + 0 + 0 + + + + Break On + + + + + + First chance + + + + + + + Second chance + + + + + + + Do not break + + + + + + + + + + Logging + + + + + + Log exception + + + + + + + + + + Exception handled by + + + + + + Debugger + + + + + + + Debuggee + + + + + + @@ -1007,9 +1082,9 @@ chkDisableDatabaseCompression chkSaveDatabaseInProgramDirectory listExceptions - btnAddRange + btnIgnoreRange btnDeleteRange - btnAddLast + btnIgnoreLast chkArgumentSpaces chkTabBetweenMnemonicAndArguments chkMemorySpaces From 93794bf8cfcc119557fb55d0e75a572daaacf916 Mon Sep 17 00:00:00 2001 From: Matthijs Lavrijsen Date: Fri, 29 Jan 2021 11:33:29 +0100 Subject: [PATCH 2/3] DBG: add more fine-grained exception filtering settings --- src/dbg/_exports.cpp | 40 ++++++++++++++++++++---- src/dbg/debugger.cpp | 73 ++++++++++++++++++++++++++++++-------------- src/dbg/debugger.h | 28 +++++++++++++++-- 3 files changed, 109 insertions(+), 32 deletions(-) diff --git a/src/dbg/_exports.cpp b/src/dbg/_exports.cpp index ba147aa2..11b7b3ee 100644 --- a/src/dbg/_exports.cpp +++ b/src/dbg/_exports.cpp @@ -1056,7 +1056,8 @@ extern "C" DLL_EXPORT duint _dbg_sendmessage(DBGMSG type, void* param1, void* pa } std::vector settingText(MAX_SETTING_SIZE + 1, '\0'); - dbgclearignoredexceptions(); + bool unknownExceptionsFilterAdded = false; + dbgclearexceptionfilters(); if(BridgeSettingGet("Exceptions", "IgnoreRange", settingText.data())) { char* context = nullptr; @@ -1065,16 +1066,43 @@ extern "C" DLL_EXPORT duint _dbg_sendmessage(DBGMSG type, void* param1, void* pa { unsigned long start; unsigned long end; - if(sscanf_s(entry, "%08X-%08X", &start, &end) == 2 && start <= end) + if(strstr(entry, "debug") == nullptr && // check for old ignore format + sscanf_s(entry, "%08X-%08X", &start, &end) == 2 && start <= end) { - ExceptionRange range; - range.start = start; - range.end = end; - dbgaddignoredexception(range); + ExceptionFilter filter; + filter.range.start = start; + filter.range.end = end; + // Default settings for an ignore entry + filter.breakOn = ExceptionBreakOn::SecondChance; + filter.logException = true; + filter.handledBy = ExceptionHandledBy::Debuggee; + dbgaddexceptionfilter(filter); + } + else if(strstr(entry, "debug") != nullptr && // new filter format + sscanf_s(entry, "%08X-%08X", &start, &end) == 2 && start <= end) + { + ExceptionFilter filter; + filter.range.start = start; + filter.range.end = end; + filter.breakOn = strstr(entry, "first") != nullptr ? ExceptionBreakOn::FirstChance : strstr(entry, "second") != nullptr ? ExceptionBreakOn::SecondChance : ExceptionBreakOn::DoNotBreak; + filter.logException = strstr(entry, "nolog") == nullptr; + filter.handledBy = strstr(entry, "debugger") != nullptr ? ExceptionHandledBy::Debugger : ExceptionHandledBy::Debuggee; + dbgaddexceptionfilter(filter); + if(filter.range.start == 0 && filter.range.start == filter.range.end) + unknownExceptionsFilterAdded = true; } entry = strtok_s(nullptr, ",", &context); } } + if(!unknownExceptionsFilterAdded) // add a default filter for unknown exceptions if it was not yet present in settings + { + ExceptionFilter unknownExceptionsFilter; + unknownExceptionsFilter.range.start = unknownExceptionsFilter.range.end = 0; + unknownExceptionsFilter.breakOn = ExceptionBreakOn::FirstChance; + unknownExceptionsFilter.logException = true; + unknownExceptionsFilter.handledBy = ExceptionHandledBy::Debuggee; + dbgaddexceptionfilter(unknownExceptionsFilter); + } if(BridgeSettingGet("Symbols", "CachePath", settingText.data())) { diff --git a/src/dbg/debugger.cpp b/src/dbg/debugger.cpp index 9fdc9115..84afb88f 100644 --- a/src/dbg/debugger.cpp +++ b/src/dbg/debugger.cpp @@ -52,7 +52,7 @@ static bool bIsAttached = false; static bool bSkipExceptions = false; static duint skipExceptionCount = 0; static bool bFreezeStack = false; -static std::vector ignoredExceptionRange; +static std::vector exceptionFilters; static HANDLE hEvent = 0; static duint tidToResume = 0; static HANDLE hMemMapThread = 0; @@ -331,26 +331,43 @@ void dbgsetfreezestack(bool freeze) bFreezeStack = freeze; } -void dbgclearignoredexceptions() +void dbgclearexceptionfilters() { - ignoredExceptionRange.clear(); + exceptionFilters.clear(); } -void dbgaddignoredexception(ExceptionRange range) +void dbgaddexceptionfilter(ExceptionFilter filter) { - ignoredExceptionRange.push_back(range); + exceptionFilters.push_back(filter); } -bool dbgisignoredexception(unsigned int exception) +const ExceptionFilter & dbggetexceptionfilter(unsigned int exception) { - for(unsigned int i = 0; i < ignoredExceptionRange.size(); i++) + for(unsigned int i = 0; i < exceptionFilters.size(); i++) { - unsigned int curStart = ignoredExceptionRange.at(i).start; - unsigned int curEnd = ignoredExceptionRange.at(i).end; + const ExceptionFilter & filter = exceptionFilters.at(i); + unsigned int curStart = filter.range.start; + unsigned int curEnd = filter.range.end; if(exception >= curStart && exception <= curEnd) - return true; + return filter; } - return false; + + // no filter found, return the catch-all filter for unknown exceptions + for(unsigned int i = 0; i < exceptionFilters.size(); i++) + { + const ExceptionFilter & filter = exceptionFilters.at(i); + if(filter.range.start == 0 && filter.range.start == filter.range.end) + return filter; + } + + // the unknown exceptions filter is not yet present in settings, add it now + ExceptionFilter unknownExceptionsFilter; + unknownExceptionsFilter.range.start = unknownExceptionsFilter.range.end = 0; + unknownExceptionsFilter.breakOn = ExceptionBreakOn::FirstChance; + unknownExceptionsFilter.logException = true; + unknownExceptionsFilter.handledBy = ExceptionHandledBy::Debuggee; + exceptionFilters.push_back(unknownExceptionsFilter); + return exceptionFilters.back(); } bool dbgcmdnew(const char* name, CBCOMMAND cbCommand, bool debugonly) @@ -1956,29 +1973,39 @@ static void cbException(EXCEPTION_DEBUG_INFO* ExceptionData) } } } - if(bVerboseExceptionLogging) + const ExceptionFilter & filter = dbggetexceptionfilter(ExceptionCode); + if(bVerboseExceptionLogging && filter.logException) DbgCmdExecDirect("exinfo"); //show extended exception information auto exceptionName = ExceptionCodeToName(ExceptionCode); if(!exceptionName.size()) //if no exception was found, try the error codes (RPC_S_*) exceptionName = ErrorCodeToName(ExceptionCode); if(ExceptionData->dwFirstChance) //first chance exception { - if(exceptionName.size()) - dprintf(QT_TRANSLATE_NOOP("DBG", "First chance exception on %p (%.8X, %s)!\n"), addr, ExceptionCode, exceptionName.c_str()); - else - dprintf(QT_TRANSLATE_NOOP("DBG", "First chance exception on %p (%.8X)!\n"), addr, ExceptionCode); - SetNextDbgContinueStatus(DBG_EXCEPTION_NOT_HANDLED); - if((bSkipExceptions || dbgisignoredexception(ExceptionCode)) && (!maxSkipExceptionCount || ++skipExceptionCount < maxSkipExceptionCount)) + if(filter.logException) + { + if(exceptionName.size()) + dprintf(QT_TRANSLATE_NOOP("DBG", "First chance exception on %p (%.8X, %s)!\n"), addr, ExceptionCode, exceptionName.c_str()); + else + dprintf(QT_TRANSLATE_NOOP("DBG", "First chance exception on %p (%.8X)!\n"), addr, ExceptionCode); + } + SetNextDbgContinueStatus(filter.handledBy == ExceptionHandledBy::Debuggee ? DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE); + if((bSkipExceptions || filter.breakOn != ExceptionBreakOn::FirstChance) && (!maxSkipExceptionCount || ++skipExceptionCount < maxSkipExceptionCount)) return; } else //lock the exception { - if(exceptionName.size()) - dprintf(QT_TRANSLATE_NOOP("DBG", "Last chance exception on %p (%.8X, %s)!\n"), addr, ExceptionCode, exceptionName.c_str()); - else - dprintf(QT_TRANSLATE_NOOP("DBG", "Last chance exception on %p (%.8X)!\n"), addr, ExceptionCode); - SetNextDbgContinueStatus(DBG_CONTINUE); + if(filter.logException) + { + if(exceptionName.size()) + dprintf(QT_TRANSLATE_NOOP("DBG", "Last chance exception on %p (%.8X, %s)!\n"), addr, ExceptionCode, exceptionName.c_str()); + else + dprintf(QT_TRANSLATE_NOOP("DBG", "Last chance exception on %p (%.8X)!\n"), addr, ExceptionCode); + } + // DBG_EXCEPTION_NOT_HANDLED kills the process on a last chance exception, so only pass this if the user really asked for it + SetNextDbgContinueStatus(filter.breakOn == ExceptionBreakOn::DoNotBreak && filter.handledBy == ExceptionHandledBy::Debuggee ? DBG_EXCEPTION_NOT_HANDLED : DBG_CONTINUE); } + if(filter.breakOn == ExceptionBreakOn::DoNotBreak) + return; DebugUpdateGuiSetStateAsync(GetContextDataEx(hActiveThread, UE_CIP), true); //lock diff --git a/src/dbg/debugger.h b/src/dbg/debugger.h index beb01a08..475b3651 100644 --- a/src/dbg/debugger.h +++ b/src/dbg/debugger.h @@ -10,6 +10,20 @@ #include #include +//enums +enum class ExceptionBreakOn +{ + FirstChance, + SecondChance, + DoNotBreak +}; + +enum class ExceptionHandledBy +{ + Debugger, + Debuggee +}; + //structures struct INIT_STRUCT { @@ -24,6 +38,14 @@ struct ExceptionRange unsigned int end; }; +struct ExceptionFilter +{ + ExceptionRange range; + ExceptionBreakOn breakOn; + bool logException; + ExceptionHandledBy handledBy; +}; + #pragma pack(push,8) typedef struct _THREADNAME_INFO { @@ -55,9 +77,9 @@ void GuiSetDebugStateAsync(DBGSTATE state); void dbgsetskipexceptions(bool skip); void dbgsetsteprepeat(bool steppingIn, duint repeat); void dbgsetfreezestack(bool freeze); -void dbgclearignoredexceptions(); -void dbgaddignoredexception(ExceptionRange range); -bool dbgisignoredexception(unsigned int exception); +void dbgclearexceptionfilters(); +void dbgaddexceptionfilter(ExceptionFilter filter); +const ExceptionFilter & dbggetexceptionfilter(unsigned int exception); bool dbgcmdnew(const char* name, CBCOMMAND cbCommand, bool debugonly); bool dbgcmddel(const char* name); bool dbglistprocesses(std::vector* infoList, std::vector* commandList, std::vector* winTextList); From 515c08823e059634d3abab7f9216009ec01c2e0b Mon Sep 17 00:00:00 2001 From: Matthijs Lavrijsen Date: Fri, 29 Jan 2021 11:34:11 +0100 Subject: [PATCH 3/3] GUI: add human readable names to exceptions tab --- src/gui/Src/Gui/SettingsDialog.cpp | 27 ++++++++++++++++++++++++++- src/gui/Src/Gui/SettingsDialog.h | 1 + 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/gui/Src/Gui/SettingsDialog.cpp b/src/gui/Src/Gui/SettingsDialog.cpp index 6cb133c1..6c5bc26f 100644 --- a/src/gui/Src/Gui/SettingsDialog.cpp +++ b/src/gui/Src/Gui/SettingsDialog.cpp @@ -609,13 +609,38 @@ void SettingsDialog::UpdateExceptionListWidget() { qSort(settings.exceptionFilters->begin(), settings.exceptionFilters->end(), ExceptionFilterLess()); ui->listExceptions->clear(); + + if(exceptionNames.empty() && DbgFunctions()->EnumExceptions) + { + BridgeList exceptions; + DbgFunctions()->EnumExceptions(&exceptions); + for(int i = 0; i < exceptions.Count(); i++) + { + exceptionNames.insert({exceptions[i].value, exceptions[i].name}); + } + } + for(int i = 0; i < settings.exceptionFilters->size(); i++) { const ExceptionFilter & filter = settings.exceptionFilters->at(i); if(filter.range.start == 0 && filter.range.start == filter.range.end) ui->listExceptions->addItem(QString("Unknown exceptions")); else - ui->listExceptions->addItem(QString().asprintf("%.8X-%.8X", filter.range.start, filter.range.end)); + { + const bool bSingleItemRange = filter.range.start == filter.range.end; + if(!bSingleItemRange) + { + ui->listExceptions->addItem(QString().asprintf("%.8X-%.8X", filter.range.start, filter.range.end)); + } + else + { + auto found = exceptionNames.find(filter.range.start); + if(found == exceptionNames.end()) + ui->listExceptions->addItem(QString().asprintf("%.8X", filter.range.start)); + else + ui->listExceptions->addItem(QString().asprintf("%.8X\n %s", filter.range.start, found->second)); + } + } } } diff --git a/src/gui/Src/Gui/SettingsDialog.h b/src/gui/Src/Gui/SettingsDialog.h index 8f20261b..5e647cf7 100644 --- a/src/gui/Src/Gui/SettingsDialog.h +++ b/src/gui/Src/Gui/SettingsDialog.h @@ -250,6 +250,7 @@ private: Ui::SettingsDialog* ui; SettingsStruct settings; QList realExceptionFilters; + std::unordered_map exceptionNames; bool bJitOld; bool bJitAutoOld; bool bGuiOptionsUpdated;