boot: implement --unhandled-exception=stalldebug (#1690)

Using this option will stall the crashed thread until the debugger
attaches, so that the newly attached debugger can be handed over the
exception, enabling breaking at correct stack location.

`--no-exception-handlers` injector option controlled whether Dalamud
Crash Handler would intercept exceptions before. Those are now either
`default` or `none` option for `--unhandled-exception`.
This commit is contained in:
srkizer 2024-04-21 13:20:11 +09:00 committed by GitHub
parent b85914c54c
commit 8ff4662f1f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 101 additions and 13 deletions

View file

@ -82,6 +82,21 @@ void from_json(const nlohmann::json& json, DalamudStartInfo::LoadMethod& value)
}
}
void from_json(const nlohmann::json& json, DalamudStartInfo::UnhandledExceptionHandlingMode& value) {
if (json.is_number_integer()) {
value = static_cast<DalamudStartInfo::UnhandledExceptionHandlingMode>(json.get<int>());
} else if (json.is_string()) {
const auto langstr = unicode::convert<std::string>(json.get<std::string>(), &unicode::lower);
if (langstr == "default")
value = DalamudStartInfo::UnhandledExceptionHandlingMode::Default;
else if (langstr == "stalldebug")
value = DalamudStartInfo::UnhandledExceptionHandlingMode::StallDebug;
else if (langstr == "none")
value = DalamudStartInfo::UnhandledExceptionHandlingMode::None;
}
}
void from_json(const nlohmann::json& json, DalamudStartInfo& config) {
if (!json.is_object())
return;
@ -121,7 +136,7 @@ void from_json(const nlohmann::json& json, DalamudStartInfo& config) {
}
config.CrashHandlerShow = json.value("CrashHandlerShow", config.CrashHandlerShow);
config.NoExceptionHandlers = json.value("NoExceptionHandlers", config.NoExceptionHandlers);
config.UnhandledException = json.value("UnhandledException", config.UnhandledException);
}
void DalamudStartInfo::from_envvars() {

View file

@ -32,6 +32,13 @@ struct DalamudStartInfo {
};
friend void from_json(const nlohmann::json&, LoadMethod&);
enum class UnhandledExceptionHandlingMode : int {
Default,
StallDebug,
None,
};
friend void from_json(const nlohmann::json&, UnhandledExceptionHandlingMode&);
LoadMethod DalamudLoadMethod = LoadMethod::Entrypoint;
std::string WorkingDirectory;
std::string ConfigurationPath;
@ -59,7 +66,7 @@ struct DalamudStartInfo {
std::set<std::string> BootUnhookDlls{};
bool CrashHandlerShow = false;
bool NoExceptionHandlers = false;
UnhandledExceptionHandlingMode UnhandledException = UnhandledExceptionHandlingMode::Default;
friend void from_json(const nlohmann::json&, DalamudStartInfo&);
void from_envvars();

View file

@ -133,7 +133,7 @@ HRESULT WINAPI InitializeImpl(LPVOID lpParam, HANDLE hMainThreadContinue) {
// ============================== VEH ======================================== //
logging::I("Initializing VEH...");
if (g_startInfo.NoExceptionHandlers) {
if (g_startInfo.UnhandledException == DalamudStartInfo::UnhandledExceptionHandlingMode::None) {
logging::W("=> Exception handlers are disabled from DalamudStartInfo.");
} else if (g_startInfo.BootVehEnabled) {
if (veh::add_handler(g_startInfo.BootVehFull, g_startInfo.WorkingDirectory))

View file

@ -136,6 +136,17 @@ static void append_injector_launch_args(std::vector<std::wstring>& args)
args.emplace_back(L"--msgbox2");
if ((g_startInfo.BootWaitMessageBox & DalamudStartInfo::WaitMessageboxFlags::BeforeDalamudConstruct) != DalamudStartInfo::WaitMessageboxFlags::None)
args.emplace_back(L"--msgbox3");
switch (g_startInfo.UnhandledException) {
case DalamudStartInfo::UnhandledExceptionHandlingMode::Default:
args.emplace_back(L"--unhandled-exception=default");
break;
case DalamudStartInfo::UnhandledExceptionHandlingMode::StallDebug:
args.emplace_back(L"--unhandled-exception=stalldebug");
break;
case DalamudStartInfo::UnhandledExceptionHandlingMode::None:
args.emplace_back(L"--unhandled-exception=none");
break;
}
args.emplace_back(L"--");
@ -148,6 +159,13 @@ static void append_injector_launch_args(std::vector<std::wstring>& args)
LONG exception_handler(EXCEPTION_POINTERS* ex)
{
if (g_startInfo.UnhandledException == DalamudStartInfo::UnhandledExceptionHandlingMode::StallDebug) {
while (!IsDebuggerPresent())
Sleep(100);
return EXCEPTION_CONTINUE_SEARCH;
}
// block any other exceptions hitting the handler while the messagebox is open
const auto lock = std::lock_guard(g_exception_handler_mutex);