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 = []
|
||||
powder_deps = []
|
||||
|
||||
project_export_dynamic = false
|
||||
|
||||
subdir('src')
|
||||
subdir('resources')
|
||||
|
||||
@ -411,6 +413,7 @@ if get_option('build_powder')
|
||||
win_subsystem: is_debug ? 'console' : 'windows',
|
||||
link_args: project_link_args,
|
||||
dependencies: powder_deps,
|
||||
export_dynamic: project_export_dynamic,
|
||||
install: true,
|
||||
)
|
||||
endif
|
||||
@ -439,6 +442,7 @@ if get_option('build_render')
|
||||
cpp_args: project_cpp_args,
|
||||
link_args: render_link_args,
|
||||
dependencies: render_deps,
|
||||
export_dynamic: project_export_dynamic,
|
||||
)
|
||||
endif
|
||||
|
||||
@ -462,5 +466,6 @@ if get_option('build_font')
|
||||
cpp_args: project_cpp_args,
|
||||
link_args: project_link_args,
|
||||
dependencies: font_deps,
|
||||
export_dynamic: project_export_dynamic,
|
||||
)
|
||||
endif
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "gui/dialogues/ConfirmPrompt.h"
|
||||
#include "gui/dialogues/ErrorMessage.h"
|
||||
#include "gui/interface/Engine.h"
|
||||
#include "gui/interface/TextWrapper.h"
|
||||
#include "Config.h"
|
||||
#include "SimulationConfig.h"
|
||||
#include <optional>
|
||||
@ -104,11 +105,6 @@ static void BlueScreen(String detailMessage, std::optional<std::vector<String>>
|
||||
auto &engine = ui::Engine::Ref();
|
||||
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 crashLogPath = ByteString("crash.log");
|
||||
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";
|
||||
}
|
||||
addParapgraph(crashInfo.Build());
|
||||
|
||||
engine.g->BlendText(ui::Point((engine.g->Size().X - 440) / 2, 80), errorText, 0xFFFFFF_rgb .WithAlpha(0xFF));
|
||||
String errorText = crashInfo.Build();
|
||||
constexpr auto width = 440;
|
||||
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();
|
||||
std::cerr << crashLogData << std::endl;
|
||||
Platform::WriteFile(std::vector<char>(crashLogData.begin(), crashLogData.end()), crashLogPath);
|
||||
|
||||
//Death loop
|
||||
|
@ -78,10 +78,15 @@ else
|
||||
)
|
||||
endif
|
||||
|
||||
bluescreen_export_symbols = false
|
||||
|
||||
subdir('stacktrace')
|
||||
|
||||
if use_bluescreen
|
||||
common_files += stacktrace_files
|
||||
if bluescreen_export_symbols
|
||||
project_export_dynamic = true
|
||||
endif
|
||||
else
|
||||
common_files += files('stacktrace/Null.cpp')
|
||||
endif
|
||||
|
@ -3,6 +3,8 @@
|
||||
#include <execinfo.h>
|
||||
#include <cstdint>
|
||||
#include <array>
|
||||
#include <cxxabi.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace Platform
|
||||
{
|
||||
@ -19,7 +21,27 @@ std::optional<std::vector<String>> StackTrace()
|
||||
{
|
||||
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
|
||||
{
|
||||
|
@ -7,9 +7,46 @@
|
||||
#include <psapi.h>
|
||||
#include <array>
|
||||
#include <mutex>
|
||||
#include <cstdint>
|
||||
|
||||
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()
|
||||
{
|
||||
static std::mutex mx;
|
||||
@ -22,13 +59,11 @@ std::optional<std::vector<String>> StackTrace()
|
||||
});
|
||||
SymInitialize(process, NULL, TRUE);
|
||||
|
||||
CONTEXT context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
CONTEXT context{};
|
||||
context.ContextFlags = CONTEXT_FULL;
|
||||
RtlCaptureContext(&context);
|
||||
|
||||
STACKFRAME64 frame;
|
||||
memset(&frame, 0, sizeof(frame));
|
||||
STACKFRAME64 frame{};
|
||||
DWORD machine;
|
||||
#if defined(_M_IX86)
|
||||
machine = IMAGE_FILE_MACHINE_I386;
|
||||
@ -71,24 +106,29 @@ std::optional<std::vector<String>> StackTrace()
|
||||
std::vector<String> res;
|
||||
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;
|
||||
}
|
||||
auto offset = uintptr_t(frame.AddrPC.Offset);
|
||||
StringBuilder addr;
|
||||
addr << "0x" << Format::Hex() << uintptr_t(frame.AddrPC.Offset);
|
||||
std::array<wchar_t, 1000> moduleBaseName;
|
||||
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)))
|
||||
addr << Format::Hex();
|
||||
if (auto moduleInfo = GetModuleInfo(process, offset))
|
||||
{
|
||||
auto offset = uintptr_t(frame.AddrPC.Offset) - uintptr_t(moduleInfo.lpBaseOfDll);
|
||||
if (offset < moduleInfo.SizeOfImage)
|
||||
addr << moduleInfo->name << "(";
|
||||
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());
|
||||
}
|
||||
|
@ -9,9 +9,13 @@ if host_platform == 'windows'
|
||||
elif host_platform == 'darwin'
|
||||
# TODO: good impl; current one is only slightly better than nothing
|
||||
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'
|
||||
# TODO: again, this is more like "posix" than "linux"
|
||||
stacktrace_files = files('Execinfo.cpp')
|
||||
# export symbols so backtrace_symbols works, see above
|
||||
bluescreen_export_symbols = true
|
||||
else
|
||||
stacktrace_files = files('Null.cpp')
|
||||
endif
|
||||
|
Loading…
Reference in New Issue
Block a user