1
0
Fork 0

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
This commit is contained in:
Matthijs Lavrijsen 2021-01-29 11:32:20 +01:00
parent 5b43c22a64
commit 29205263b5
No known key found for this signature in database
GPG Key ID: D40D1DBE299B83EA
3 changed files with 312 additions and 51 deletions

View File

@ -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)

View File

@ -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,7 @@ private:
//variables
Ui::SettingsDialog* ui;
SettingsStruct settings;
QList<RangeStruct> realExceptionRanges;
QList<ExceptionFilter> 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

View File

@ -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 &amp;Range</string>
<string>Ignore &amp;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 &amp;Last</string>
<string>Ignore &amp;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>