Merge pull request #2586 from Mattiwatti/exception-filters
Make Exceptions Great Again
This commit is contained in:
commit
b7e50aa3a2
|
@ -1056,7 +1056,8 @@ extern "C" DLL_EXPORT duint _dbg_sendmessage(DBGMSG type, void* param1, void* pa
|
|||
}
|
||||
|
||||
std::vector<char> 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()))
|
||||
{
|
||||
|
|
|
@ -52,7 +52,7 @@ static bool bIsAttached = false;
|
|||
static bool bSkipExceptions = false;
|
||||
static duint skipExceptionCount = 0;
|
||||
static bool bFreezeStack = false;
|
||||
static std::vector<ExceptionRange> ignoredExceptionRange;
|
||||
static std::vector<ExceptionFilter> 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
|
||||
|
|
|
@ -10,6 +10,20 @@
|
|||
#include <tlhelp32.h>
|
||||
#include <psapi.h>
|
||||
|
||||
//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<PROCESSENTRY32>* infoList, std::vector<std::string>* commandList, std::vector<std::string>* winTextList);
|
||||
|
|
|
@ -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,127 @@ 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));
|
||||
|
||||
if(exceptionNames.empty() && DbgFunctions()->EnumExceptions)
|
||||
{
|
||||
BridgeList<CONSTANTINFO> 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
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDialog::setLastException(unsigned int exceptionCode)
|
||||
|
@ -724,15 +855,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 +875,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 +890,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)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define SETTINGSDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QListWidgetItem>
|
||||
#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<RangeStruct>* exceptionRanges;
|
||||
QList<ExceptionFilter>* exceptionFilters;
|
||||
//Disasm Tab
|
||||
bool disasmArgumentSpaces;
|
||||
bool disasmMemorySpaces;
|
||||
|
@ -219,7 +249,8 @@ private:
|
|||
//variables
|
||||
Ui::SettingsDialog* ui;
|
||||
SettingsStruct settings;
|
||||
QList<RangeStruct> realExceptionRanges;
|
||||
QList<ExceptionFilter> realExceptionFilters;
|
||||
std::unordered_map<duint, const char*> exceptionNames;
|
||||
bool bJitOld;
|
||||
bool bJitAutoOld;
|
||||
bool bGuiOptionsUpdated;
|
||||
|
@ -230,7 +261,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
|
||||
|
|
|
@ -466,9 +466,9 @@
|
|||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QLabel" name="lblIgnoredExceptions">
|
||||
<widget class="QLabel" name="lblExceptionFilters">
|
||||
<property name="text">
|
||||
<string>Ignored Exceptions:</string>
|
||||
<string>Exception Filters:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -503,9 +503,9 @@
|
|||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnAddRange">
|
||||
<widget class="QPushButton" name="btnIgnoreRange">
|
||||
<property name="text">
|
||||
<string>Add &Range</string>
|
||||
<string>Ignore &Range</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -517,12 +517,87 @@
|
|||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="btnAddLast">
|
||||
<widget class="QPushButton" name="btnIgnoreLast">
|
||||
<property name="text">
|
||||
<string>Add &Last</string>
|
||||
<string>Ignore &Last</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBoBreakOn">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Break On</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioFirstChance">
|
||||
<property name="text">
|
||||
<string>First chance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioSecondChance">
|
||||
<property name="text">
|
||||
<string>Second chance</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioDoNotBreak">
|
||||
<property name="text">
|
||||
<string>Do not break</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBoxLogging">
|
||||
<property name="title">
|
||||
<string>Logging</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkLogException">
|
||||
<property name="text">
|
||||
<string>Log exception</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBoxExceptionHandledBy">
|
||||
<property name="title">
|
||||
<string>Exception handled by</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioHandledByDebugger">
|
||||
<property name="text">
|
||||
<string>Debugger</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioHandledByDebuggee">
|
||||
<property name="text">
|
||||
<string>Debuggee</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacerExceptionsBottom">
|
||||
<property name="orientation">
|
||||
|
@ -1007,9 +1082,9 @@
|
|||
<tabstop>chkDisableDatabaseCompression</tabstop>
|
||||
<tabstop>chkSaveDatabaseInProgramDirectory</tabstop>
|
||||
<tabstop>listExceptions</tabstop>
|
||||
<tabstop>btnAddRange</tabstop>
|
||||
<tabstop>btnIgnoreRange</tabstop>
|
||||
<tabstop>btnDeleteRange</tabstop>
|
||||
<tabstop>btnAddLast</tabstop>
|
||||
<tabstop>btnIgnoreLast</tabstop>
|
||||
<tabstop>chkArgumentSpaces</tabstop>
|
||||
<tabstop>chkTabBetweenMnemonicAndArguments</tabstop>
|
||||
<tabstop>chkMemorySpaces</tabstop>
|
||||
|
|
Loading…
Reference in New Issue