Fix bluescreen stack trace not showing exception frames
This commit is contained in:
parent
ba056746b8
commit
5411269fb2
@ -29,6 +29,8 @@
|
||||
#include <iostream>
|
||||
#include <csignal>
|
||||
#include <SDL.h>
|
||||
#include <exception>
|
||||
#include <cstdlib>
|
||||
|
||||
void LoadWindowPosition()
|
||||
{
|
||||
@ -97,7 +99,7 @@ void TickClient()
|
||||
Client::Ref().Tick();
|
||||
}
|
||||
|
||||
void BlueScreen(String detailMessage, std::optional<std::vector<String>> stackTrace)
|
||||
static void BlueScreen(String detailMessage, std::optional<std::vector<String>> stackTrace)
|
||||
{
|
||||
auto &engine = ui::Engine::Ref();
|
||||
engine.g->BlendFilledRect(engine.g->Size().OriginRect(), 0x1172A9_rgb .WithAlpha(0xD2));
|
||||
@ -140,16 +142,29 @@ void BlueScreen(String detailMessage, std::optional<std::vector<String>> stackTr
|
||||
|
||||
//Death loop
|
||||
SDL_Event event;
|
||||
while(true)
|
||||
auto running = true;
|
||||
while (running)
|
||||
{
|
||||
while (SDL_PollEvent(&event))
|
||||
if(event.type == SDL_QUIT)
|
||||
exit(-1); // Don't use Platform::Exit, we're practically zombies at this point anyway.
|
||||
{
|
||||
if (event.type == SDL_QUIT)
|
||||
{
|
||||
running = false;
|
||||
}
|
||||
}
|
||||
blit(engine.g->Data());
|
||||
}
|
||||
|
||||
// Don't use Platform::Exit, we're practically zombies at this point anyway.
|
||||
#if defined(__MINGW32__) || defined(__APPLE__)
|
||||
// Come on...
|
||||
exit(-1);
|
||||
#else
|
||||
quick_exit(-1);
|
||||
#endif
|
||||
}
|
||||
|
||||
struct
|
||||
static struct
|
||||
{
|
||||
int sig;
|
||||
const char *message;
|
||||
@ -161,7 +176,7 @@ struct
|
||||
{ 0, nullptr },
|
||||
};
|
||||
|
||||
void SigHandler(int signal)
|
||||
static void SigHandler(int signal)
|
||||
{
|
||||
const char *message = "Unknown signal";
|
||||
for (auto *msg = signalMessages; msg->message; ++msg)
|
||||
@ -172,7 +187,29 @@ void SigHandler(int signal)
|
||||
break;
|
||||
}
|
||||
}
|
||||
BlueScreen(ByteString(message).FromUtf8(), Platform::StackTrace(Platform::stackTraceFromHere));
|
||||
BlueScreen(ByteString(message).FromUtf8(), Platform::StackTrace());
|
||||
}
|
||||
|
||||
static void TerminateHandler()
|
||||
{
|
||||
ByteString err = "std::terminate called without a current exception";
|
||||
auto eptr = std::current_exception();
|
||||
try
|
||||
{
|
||||
if (eptr)
|
||||
{
|
||||
std::rethrow_exception(eptr);
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
err = "unhandled exception: " + ByteString(e.what());
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
err = "unhandled exception not derived from std::exception, cannot determine reason";
|
||||
}
|
||||
BlueScreen(err.FromUtf8(), Platform::StackTrace());
|
||||
}
|
||||
|
||||
constexpr int SCALE_MAXIMUM = 10;
|
||||
@ -431,6 +468,7 @@ int Main(int argc, char *argv[])
|
||||
{
|
||||
signal(msg->sig, SigHandler);
|
||||
}
|
||||
std::set_terminate(TerminateHandler);
|
||||
}
|
||||
|
||||
if constexpr (X86)
|
||||
@ -438,114 +476,97 @@ int Main(int argc, char *argv[])
|
||||
X86KillDenormals();
|
||||
}
|
||||
|
||||
auto wrapWithBluescreen = [&]() {
|
||||
explicitSingletons->simulationData = std::make_unique<SimulationData>();
|
||||
explicitSingletons->gameController = std::make_unique<GameController>();
|
||||
auto *gameController = explicitSingletons->gameController.get();
|
||||
engine.ShowWindow(gameController->GetView());
|
||||
explicitSingletons->simulationData = std::make_unique<SimulationData>();
|
||||
explicitSingletons->gameController = std::make_unique<GameController>();
|
||||
auto *gameController = explicitSingletons->gameController.get();
|
||||
engine.ShowWindow(gameController->GetView());
|
||||
|
||||
auto openArg = arguments["open"];
|
||||
if (openArg.has_value())
|
||||
auto openArg = arguments["open"];
|
||||
if (openArg.has_value())
|
||||
{
|
||||
if constexpr (DEBUG)
|
||||
{
|
||||
if constexpr (DEBUG)
|
||||
{
|
||||
std::cout << "Loading " << openArg.value() << std::endl;
|
||||
}
|
||||
if (Platform::FileExists(openArg.value()))
|
||||
{
|
||||
try
|
||||
{
|
||||
std::vector<char> gameSaveData;
|
||||
if (!Platform::ReadFile(gameSaveData, openArg.value()))
|
||||
{
|
||||
new ErrorMessage("Error", "Could not read file");
|
||||
}
|
||||
else
|
||||
{
|
||||
auto newFile = std::make_unique<SaveFile>(openArg.value());
|
||||
auto newSave = std::make_unique<GameSave>(std::move(gameSaveData));
|
||||
newFile->SetGameSave(std::move(newSave));
|
||||
gameController->LoadSaveFile(std::move(newFile));
|
||||
}
|
||||
|
||||
}
|
||||
catch (std::exception & e)
|
||||
{
|
||||
new ErrorMessage("Error", "Could not open save file:\n" + ByteString(e.what()).FromUtf8()) ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
new ErrorMessage("Error", "Could not open file");
|
||||
}
|
||||
std::cout << "Loading " << openArg.value() << std::endl;
|
||||
}
|
||||
|
||||
auto ptsaveArg = arguments["ptsave"];
|
||||
if (ptsaveArg.has_value())
|
||||
if (Platform::FileExists(openArg.value()))
|
||||
{
|
||||
engine.g->Clear();
|
||||
engine.g->DrawRect(RectSized(engine.g->Size() / 2 - Vec2(100, 25), Vec2(200, 50)), 0xB4B4B4_rgb);
|
||||
String loadingText = "Loading save...";
|
||||
engine.g->BlendText(engine.g->Size() / 2 - Vec2((Graphics::TextSize(loadingText).X - 1) / 2, 5), loadingText, style::Colour::InformationTitle);
|
||||
|
||||
blit(engine.g->Data());
|
||||
try
|
||||
{
|
||||
ByteString saveIdPart;
|
||||
if (ByteString::Split split = ptsaveArg.value().SplitBy(':'))
|
||||
std::vector<char> gameSaveData;
|
||||
if (!Platform::ReadFile(gameSaveData, openArg.value()))
|
||||
{
|
||||
if (split.Before() != "ptsave")
|
||||
throw std::runtime_error("Not a ptsave link");
|
||||
saveIdPart = split.After().SplitBy('#').Before();
|
||||
new ErrorMessage("Error", "Could not read file");
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Invalid save link");
|
||||
{
|
||||
auto newFile = std::make_unique<SaveFile>(openArg.value());
|
||||
auto newSave = std::make_unique<GameSave>(std::move(gameSaveData));
|
||||
newFile->SetGameSave(std::move(newSave));
|
||||
gameController->LoadSaveFile(std::move(newFile));
|
||||
}
|
||||
|
||||
if (!saveIdPart.size())
|
||||
throw std::runtime_error("No Save ID");
|
||||
if constexpr (DEBUG)
|
||||
{
|
||||
std::cout << "Got Ptsave: id: " << saveIdPart << std::endl;
|
||||
}
|
||||
ByteString saveHistoryPart = "0";
|
||||
if (auto split = saveIdPart.SplitBy('@'))
|
||||
{
|
||||
saveHistoryPart = split.After();
|
||||
saveIdPart = split.Before();
|
||||
}
|
||||
int saveId = saveIdPart.ToNumber<int>();
|
||||
int saveHistory = saveHistoryPart.ToNumber<int>();
|
||||
gameController->OpenSavePreview(saveId, saveHistory, savePreviewUrl);
|
||||
}
|
||||
catch (std::exception & e)
|
||||
{
|
||||
new ErrorMessage("Error", ByteString(e.what()).FromUtf8());
|
||||
Platform::MarkPresentable();
|
||||
new ErrorMessage("Error", "Could not open save file:\n" + ByteString(e.what()).FromUtf8()) ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Platform::MarkPresentable();
|
||||
new ErrorMessage("Error", "Could not open file");
|
||||
}
|
||||
}
|
||||
|
||||
MainLoop();
|
||||
};
|
||||
|
||||
if (enableBluescreen)
|
||||
auto ptsaveArg = arguments["ptsave"];
|
||||
if (ptsaveArg.has_value())
|
||||
{
|
||||
engine.g->Clear();
|
||||
engine.g->DrawRect(RectSized(engine.g->Size() / 2 - Vec2(100, 25), Vec2(200, 50)), 0xB4B4B4_rgb);
|
||||
String loadingText = "Loading save...";
|
||||
engine.g->BlendText(engine.g->Size() / 2 - Vec2((Graphics::TextSize(loadingText).X - 1) / 2, 5), loadingText, style::Colour::InformationTitle);
|
||||
|
||||
blit(engine.g->Data());
|
||||
try
|
||||
{
|
||||
wrapWithBluescreen();
|
||||
ByteString saveIdPart;
|
||||
if (ByteString::Split split = ptsaveArg.value().SplitBy(':'))
|
||||
{
|
||||
if (split.Before() != "ptsave")
|
||||
throw std::runtime_error("Not a ptsave link");
|
||||
saveIdPart = split.After().SplitBy('#').Before();
|
||||
}
|
||||
else
|
||||
throw std::runtime_error("Invalid save link");
|
||||
|
||||
if (!saveIdPart.size())
|
||||
throw std::runtime_error("No Save ID");
|
||||
if constexpr (DEBUG)
|
||||
{
|
||||
std::cout << "Got Ptsave: id: " << saveIdPart << std::endl;
|
||||
}
|
||||
ByteString saveHistoryPart = "0";
|
||||
if (auto split = saveIdPart.SplitBy('@'))
|
||||
{
|
||||
saveHistoryPart = split.After();
|
||||
saveIdPart = split.Before();
|
||||
}
|
||||
int saveId = saveIdPart.ToNumber<int>();
|
||||
int saveHistory = saveHistoryPart.ToNumber<int>();
|
||||
gameController->OpenSavePreview(saveId, saveHistory, savePreviewUrl);
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
catch (std::exception & e)
|
||||
{
|
||||
BlueScreen(ByteString(e.what()).FromUtf8(), Platform::StackTrace(Platform::stackTraceFromException));
|
||||
new ErrorMessage("Error", ByteString(e.what()).FromUtf8());
|
||||
Platform::MarkPresentable();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
wrapWithBluescreen();
|
||||
Platform::MarkPresentable();
|
||||
}
|
||||
|
||||
MainLoop();
|
||||
|
||||
Platform::Exit(0);
|
||||
return 0;
|
||||
}
|
||||
|
@ -69,12 +69,7 @@ namespace Platform
|
||||
|
||||
int InvokeMain(int argc, char *argv[]);
|
||||
|
||||
enum StackTraceType
|
||||
{
|
||||
stackTraceFromHere,
|
||||
stackTraceFromException,
|
||||
};
|
||||
std::optional<std::vector<String>> StackTrace(StackTraceType StackTraceType);
|
||||
std::optional<std::vector<String>> StackTrace();
|
||||
|
||||
void MarkPresentable();
|
||||
}
|
||||
|
@ -6,7 +6,7 @@
|
||||
|
||||
namespace Platform
|
||||
{
|
||||
std::optional<std::vector<String>> StackTrace(StackTraceType)
|
||||
std::optional<std::vector<String>> StackTrace()
|
||||
{
|
||||
std::array<void *, 100> buf;
|
||||
auto used = backtrace(&buf[0], buf.size());
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
namespace Platform
|
||||
{
|
||||
std::optional<std::vector<String>> StackTrace(StackTraceType)
|
||||
std::optional<std::vector<String>> StackTrace()
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
|
@ -8,23 +8,9 @@
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
extern "C" void **__cdecl __current_exception_context();
|
||||
#endif
|
||||
|
||||
static CONTEXT *CurrentExceptionContext()
|
||||
{
|
||||
// TODO: find the corresponding hack for mingw and older msvc; stack traces printed for exceptions are broken without it
|
||||
CONTEXT **pctx = nullptr;
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
pctx = (CONTEXT **)__current_exception_context();
|
||||
#endif
|
||||
return pctx ? *pctx : nullptr;
|
||||
}
|
||||
|
||||
namespace Platform
|
||||
{
|
||||
std::optional<std::vector<String>> StackTrace(StackTraceType stackTraceType)
|
||||
std::optional<std::vector<String>> StackTrace()
|
||||
{
|
||||
static std::mutex mx;
|
||||
std::unique_lock lk(mx);
|
||||
@ -38,27 +24,8 @@ std::optional<std::vector<String>> StackTrace(StackTraceType stackTraceType)
|
||||
|
||||
CONTEXT context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
switch (stackTraceType)
|
||||
{
|
||||
case stackTraceFromException:
|
||||
if (auto *ec = CurrentExceptionContext())
|
||||
{
|
||||
if (ec->ContextFlags)
|
||||
{
|
||||
context = *ec;
|
||||
}
|
||||
}
|
||||
if (!context.ContextFlags)
|
||||
{
|
||||
return std::nullopt;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
RtlCaptureContext(&context);
|
||||
break;
|
||||
}
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
RtlCaptureContext(&context);
|
||||
|
||||
STACKFRAME64 frame;
|
||||
memset(&frame, 0, sizeof(frame));
|
||||
|
@ -7,8 +7,8 @@ if host_platform == 'windows'
|
||||
endif
|
||||
stacktrace_files = files('Windows.cpp')
|
||||
elif host_platform == 'darwin'
|
||||
# stacktrace_files = files('Execinfo.cpp') # macos has this but it's useless >_>
|
||||
stacktrace_files = files('Null.cpp')
|
||||
# TODO: good impl; current one is only slightly better than nothing
|
||||
stacktrace_files = files('Execinfo.cpp')
|
||||
elif host_platform == 'linux'
|
||||
# TODO: again, this is more like "posix" than "linux"
|
||||
stacktrace_files = files('Execinfo.cpp')
|
||||
|
Reference in New Issue
Block a user