DBG: add more fine-grained exception filtering settings
This commit is contained in:
parent
29205263b5
commit
93794bf8cf
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue