Attempt to show and demangle symbols in bluescreen stack traces
This commit is contained in:
parent
9a05e56f15
commit
d05b0093b9
@ -365,6 +365,8 @@ project_deps = []
|
|||||||
data_files = []
|
data_files = []
|
||||||
powder_deps = []
|
powder_deps = []
|
||||||
|
|
||||||
|
project_export_dynamic = false
|
||||||
|
|
||||||
subdir('src')
|
subdir('src')
|
||||||
subdir('resources')
|
subdir('resources')
|
||||||
|
|
||||||
@ -411,6 +413,7 @@ if get_option('build_powder')
|
|||||||
win_subsystem: is_debug ? 'console' : 'windows',
|
win_subsystem: is_debug ? 'console' : 'windows',
|
||||||
link_args: project_link_args,
|
link_args: project_link_args,
|
||||||
dependencies: powder_deps,
|
dependencies: powder_deps,
|
||||||
|
export_dynamic: project_export_dynamic,
|
||||||
install: true,
|
install: true,
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
@ -439,6 +442,7 @@ if get_option('build_render')
|
|||||||
cpp_args: project_cpp_args,
|
cpp_args: project_cpp_args,
|
||||||
link_args: render_link_args,
|
link_args: render_link_args,
|
||||||
dependencies: render_deps,
|
dependencies: render_deps,
|
||||||
|
export_dynamic: project_export_dynamic,
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -462,5 +466,6 @@ if get_option('build_font')
|
|||||||
cpp_args: project_cpp_args,
|
cpp_args: project_cpp_args,
|
||||||
link_args: project_link_args,
|
link_args: project_link_args,
|
||||||
dependencies: font_deps,
|
dependencies: font_deps,
|
||||||
|
export_dynamic: project_export_dynamic,
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include "gui/dialogues/ConfirmPrompt.h"
|
#include "gui/dialogues/ConfirmPrompt.h"
|
||||||
#include "gui/dialogues/ErrorMessage.h"
|
#include "gui/dialogues/ErrorMessage.h"
|
||||||
#include "gui/interface/Engine.h"
|
#include "gui/interface/Engine.h"
|
||||||
|
#include "gui/interface/TextWrapper.h"
|
||||||
#include "Config.h"
|
#include "Config.h"
|
||||||
#include "SimulationConfig.h"
|
#include "SimulationConfig.h"
|
||||||
#include <optional>
|
#include <optional>
|
||||||
@ -104,11 +105,6 @@ static void BlueScreen(String detailMessage, std::optional<std::vector<String>>
|
|||||||
auto &engine = ui::Engine::Ref();
|
auto &engine = ui::Engine::Ref();
|
||||||
engine.g->BlendFilledRect(engine.g->Size().OriginRect(), 0x1172A9_rgb .WithAlpha(0xD2));
|
engine.g->BlendFilledRect(engine.g->Size().OriginRect(), 0x1172A9_rgb .WithAlpha(0xD2));
|
||||||
|
|
||||||
String errorText;
|
|
||||||
auto addParapgraph = [&errorText](String str) {
|
|
||||||
errorText += str + "\n\n";
|
|
||||||
};
|
|
||||||
|
|
||||||
auto crashPrevLogPath = ByteString("crash.prev.log");
|
auto crashPrevLogPath = ByteString("crash.prev.log");
|
||||||
auto crashLogPath = ByteString("crash.log");
|
auto crashLogPath = ByteString("crash.log");
|
||||||
Platform::RenameFile(crashLogPath, crashPrevLogPath, true);
|
Platform::RenameFile(crashLogPath, crashPrevLogPath, true);
|
||||||
@ -133,11 +129,14 @@ static void BlueScreen(String detailMessage, std::optional<std::vector<String>>
|
|||||||
{
|
{
|
||||||
crashInfo << "Stack trace not available\n";
|
crashInfo << "Stack trace not available\n";
|
||||||
}
|
}
|
||||||
addParapgraph(crashInfo.Build());
|
String errorText = crashInfo.Build();
|
||||||
|
constexpr auto width = 440;
|
||||||
engine.g->BlendText(ui::Point((engine.g->Size().X - 440) / 2, 80), errorText, 0xFFFFFF_rgb .WithAlpha(0xFF));
|
ui::TextWrapper tw;
|
||||||
|
tw.Update(errorText, true, width);
|
||||||
|
engine.g->BlendText(ui::Point((engine.g->Size().X - width) / 2, 80), tw.WrappedText(), 0xFFFFFF_rgb .WithAlpha(0xFF));
|
||||||
|
|
||||||
auto crashLogData = errorText.ToUtf8();
|
auto crashLogData = errorText.ToUtf8();
|
||||||
|
std::cerr << crashLogData << std::endl;
|
||||||
Platform::WriteFile(std::vector<char>(crashLogData.begin(), crashLogData.end()), crashLogPath);
|
Platform::WriteFile(std::vector<char>(crashLogData.begin(), crashLogData.end()), crashLogPath);
|
||||||
|
|
||||||
//Death loop
|
//Death loop
|
||||||
|
@ -78,10 +78,15 @@ else
|
|||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
bluescreen_export_symbols = false
|
||||||
|
|
||||||
subdir('stacktrace')
|
subdir('stacktrace')
|
||||||
|
|
||||||
if use_bluescreen
|
if use_bluescreen
|
||||||
common_files += stacktrace_files
|
common_files += stacktrace_files
|
||||||
|
if bluescreen_export_symbols
|
||||||
|
project_export_dynamic = true
|
||||||
|
endif
|
||||||
else
|
else
|
||||||
common_files += files('stacktrace/Null.cpp')
|
common_files += files('stacktrace/Null.cpp')
|
||||||
endif
|
endif
|
||||||
|
@ -3,6 +3,8 @@
|
|||||||
#include <execinfo.h>
|
#include <execinfo.h>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <cxxabi.h>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
namespace Platform
|
namespace Platform
|
||||||
{
|
{
|
||||||
@ -19,7 +21,27 @@ std::optional<std::vector<String>> StackTrace()
|
|||||||
{
|
{
|
||||||
if (strs)
|
if (strs)
|
||||||
{
|
{
|
||||||
res.push_back(ByteString(strs[i]).FromUtf8());
|
auto line = ByteString(strs[i]);
|
||||||
|
if (auto beginSymbolName = line.SplitBy('('))
|
||||||
|
{
|
||||||
|
auto afterBeginSymbolName = beginSymbolName.After();
|
||||||
|
if (auto endSymbolName = afterBeginSymbolName.SplitBy('+'))
|
||||||
|
{
|
||||||
|
auto beforeSymbolName = beginSymbolName.Before();
|
||||||
|
auto symbolName = endSymbolName.Before();
|
||||||
|
auto afterSymbolName = endSymbolName.After();
|
||||||
|
int status;
|
||||||
|
char *demangled = abi::__cxa_demangle(symbolName.c_str(), NULL, NULL, &status);
|
||||||
|
Defer freeDemangled([demangled]() {
|
||||||
|
free(demangled);
|
||||||
|
});
|
||||||
|
if (!status)
|
||||||
|
{
|
||||||
|
line = ByteString::Build(beforeSymbolName, "(", demangled, "+", afterSymbolName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
res.push_back(line.FromUtf8());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -7,9 +7,46 @@
|
|||||||
#include <psapi.h>
|
#include <psapi.h>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
namespace Platform
|
namespace Platform
|
||||||
{
|
{
|
||||||
|
struct SymbolInfo
|
||||||
|
{
|
||||||
|
String name;
|
||||||
|
uintptr_t displacement;
|
||||||
|
};
|
||||||
|
static std::optional<SymbolInfo> GetSymbolInfo(HANDLE process, uintptr_t offset)
|
||||||
|
{
|
||||||
|
DWORD64 displacement;
|
||||||
|
std::array<char, sizeof(SYMBOL_INFOW) + 1000> symbolData{};
|
||||||
|
auto &symbol = *reinterpret_cast<SYMBOL_INFOW *>(&symbolData[0]);
|
||||||
|
symbol.SizeOfStruct = sizeof(symbol);
|
||||||
|
symbol.MaxNameLen = symbolData.size() - sizeof(symbol);
|
||||||
|
if (SymFromAddrW(process, offset, &displacement, &symbol))
|
||||||
|
{
|
||||||
|
return SymbolInfo{ WinNarrow(&symbol.Name[0]).FromUtf8(), uintptr_t(displacement) };
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ModuleInfo
|
||||||
|
{
|
||||||
|
String name;
|
||||||
|
uintptr_t displacement;
|
||||||
|
};
|
||||||
|
static std::optional<ModuleInfo> GetModuleInfo(HANDLE process, uintptr_t offset)
|
||||||
|
{
|
||||||
|
IMAGEHLP_MODULEW64 module{};
|
||||||
|
module.SizeOfStruct = sizeof(module);
|
||||||
|
if (SymGetModuleInfoW64(process, offset, &module))
|
||||||
|
{
|
||||||
|
auto displacement = offset - uintptr_t(module.BaseOfImage);
|
||||||
|
return ModuleInfo{ WinNarrow(&module.LoadedImageName[0]).FromUtf8(), displacement };
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<std::vector<String>> StackTrace()
|
std::optional<std::vector<String>> StackTrace()
|
||||||
{
|
{
|
||||||
static std::mutex mx;
|
static std::mutex mx;
|
||||||
@ -22,13 +59,11 @@ std::optional<std::vector<String>> StackTrace()
|
|||||||
});
|
});
|
||||||
SymInitialize(process, NULL, TRUE);
|
SymInitialize(process, NULL, TRUE);
|
||||||
|
|
||||||
CONTEXT context;
|
CONTEXT context{};
|
||||||
memset(&context, 0, sizeof(context));
|
|
||||||
context.ContextFlags = CONTEXT_FULL;
|
context.ContextFlags = CONTEXT_FULL;
|
||||||
RtlCaptureContext(&context);
|
RtlCaptureContext(&context);
|
||||||
|
|
||||||
STACKFRAME64 frame;
|
STACKFRAME64 frame{};
|
||||||
memset(&frame, 0, sizeof(frame));
|
|
||||||
DWORD machine;
|
DWORD machine;
|
||||||
#if defined(_M_IX86)
|
#if defined(_M_IX86)
|
||||||
machine = IMAGE_FILE_MACHINE_I386;
|
machine = IMAGE_FILE_MACHINE_I386;
|
||||||
@ -71,24 +106,29 @@ std::optional<std::vector<String>> StackTrace()
|
|||||||
std::vector<String> res;
|
std::vector<String> res;
|
||||||
for (auto i = 0; i < 100; ++i)
|
for (auto i = 0; i < 100; ++i)
|
||||||
{
|
{
|
||||||
if (!StackWalk64( machine, process, thread, &frame, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
|
if (!StackWalk64(machine, process, thread, &frame, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
auto offset = uintptr_t(frame.AddrPC.Offset);
|
||||||
StringBuilder addr;
|
StringBuilder addr;
|
||||||
addr << "0x" << Format::Hex() << uintptr_t(frame.AddrPC.Offset);
|
addr << Format::Hex();
|
||||||
std::array<wchar_t, 1000> moduleBaseName;
|
if (auto moduleInfo = GetModuleInfo(process, offset))
|
||||||
HMODULE module;
|
|
||||||
MODULEINFO moduleInfo;
|
|
||||||
if (GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCWSTR)frame.AddrPC.Offset, &module) &&
|
|
||||||
GetModuleBaseNameW(process, module, &moduleBaseName[0], moduleBaseName.size()) &&
|
|
||||||
GetModuleInformation(process, module, &moduleInfo, sizeof(moduleInfo)))
|
|
||||||
{
|
{
|
||||||
auto offset = uintptr_t(frame.AddrPC.Offset) - uintptr_t(moduleInfo.lpBaseOfDll);
|
addr << moduleInfo->name << "(";
|
||||||
if (offset < moduleInfo.SizeOfImage)
|
if (auto symbolInfo = GetSymbolInfo(process, offset))
|
||||||
{
|
{
|
||||||
addr << " (" << WinNarrow(&moduleBaseName[0]).FromUtf8() << "+0x" << Format::Hex() << offset << ")";
|
addr << symbolInfo->name << "+0x" << symbolInfo->displacement;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addr << "+0x" << moduleInfo->displacement;
|
||||||
|
}
|
||||||
|
addr << ") [0x" << offset << "]";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
addr << "0x" << offset;
|
||||||
}
|
}
|
||||||
res.push_back(addr.Build());
|
res.push_back(addr.Build());
|
||||||
}
|
}
|
||||||
|
@ -9,9 +9,13 @@ if host_platform == 'windows'
|
|||||||
elif host_platform == 'darwin'
|
elif host_platform == 'darwin'
|
||||||
# TODO: good impl; current one is only slightly better than nothing
|
# TODO: good impl; current one is only slightly better than nothing
|
||||||
stacktrace_files = files('Execinfo.cpp')
|
stacktrace_files = files('Execinfo.cpp')
|
||||||
|
# export symbols so backtrace_symbols works, see https://www.gnu.org/software/libc/manual/html_node/Backtraces.html
|
||||||
|
bluescreen_export_symbols = true
|
||||||
elif host_platform == 'linux'
|
elif host_platform == 'linux'
|
||||||
# TODO: again, this is more like "posix" than "linux"
|
# TODO: again, this is more like "posix" than "linux"
|
||||||
stacktrace_files = files('Execinfo.cpp')
|
stacktrace_files = files('Execinfo.cpp')
|
||||||
|
# export symbols so backtrace_symbols works, see above
|
||||||
|
bluescreen_export_symbols = true
|
||||||
else
|
else
|
||||||
stacktrace_files = files('Null.cpp')
|
stacktrace_files = files('Null.cpp')
|
||||||
endif
|
endif
|
||||||
|
Loading…
Reference in New Issue
Block a user