mirror of
https://github.com/RPCS3/rpcs3.git
synced 2024-12-26 12:17:32 +00:00
151 lines
3.5 KiB
C++
151 lines
3.5 KiB
C++
#include "stdafx.h"
|
|
#include "stack_trace.h"
|
|
|
|
#ifdef _WIN32
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <Windows.h>
|
|
#define DBGHELP_TRANSLATE_TCHAR
|
|
#include <DbgHelp.h>
|
|
#include <codecvt>
|
|
#else
|
|
#include <execinfo.h>
|
|
#endif
|
|
|
|
namespace utils
|
|
{
|
|
#ifdef _WIN32
|
|
std::string wstr_to_utf8(LPWSTR data, int str_len)
|
|
{
|
|
if (!str_len)
|
|
{
|
|
return {};
|
|
}
|
|
|
|
// Calculate size
|
|
const auto length = WideCharToMultiByte(CP_UTF8, 0, data, str_len, NULL, 0, NULL, NULL);
|
|
|
|
// Convert
|
|
std::vector<char> out(length + 1, 0);
|
|
WideCharToMultiByte(CP_UTF8, 0, data, str_len, out.data(), length, NULL, NULL);
|
|
return out.data();
|
|
}
|
|
|
|
std::vector<void*> get_backtrace(int max_depth)
|
|
{
|
|
std::vector<void*> result = {};
|
|
|
|
const auto hProcess = ::GetCurrentProcess();
|
|
const auto hThread = ::GetCurrentThread();
|
|
|
|
CONTEXT context{};
|
|
RtlCaptureContext(&context);
|
|
|
|
STACKFRAME64 stack = {};
|
|
stack.AddrPC.Mode = AddrModeFlat;
|
|
stack.AddrStack.Mode = AddrModeFlat;
|
|
stack.AddrFrame.Mode = AddrModeFlat;
|
|
#if defined(ARCH_X64)
|
|
stack.AddrPC.Offset = context.Rip;
|
|
stack.AddrStack.Offset = context.Rsp;
|
|
stack.AddrFrame.Offset = context.Rbp;
|
|
#elif defined(ARCH_ARM64)
|
|
stack.AddrPC.Offset = context.Pc;
|
|
stack.AddrStack.Offset = context.Sp;
|
|
stack.AddrFrame.Offset = context.Fp;
|
|
#endif
|
|
|
|
while (max_depth--)
|
|
{
|
|
if (!StackWalk64(
|
|
IMAGE_FILE_MACHINE_AMD64,
|
|
hProcess,
|
|
hThread,
|
|
&stack,
|
|
&context,
|
|
NULL,
|
|
SymFunctionTableAccess64,
|
|
SymGetModuleBase64,
|
|
NULL))
|
|
{
|
|
break;
|
|
}
|
|
|
|
result.push_back(reinterpret_cast<void*>(stack.AddrPC.Offset));
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
std::vector<std::string> get_backtrace_symbols(const std::vector<void*>& stack)
|
|
{
|
|
std::vector<std::string> result = {};
|
|
std::vector<u8> symbol_buf(sizeof(SYMBOL_INFOW) + sizeof(TCHAR) * 256);
|
|
|
|
const auto hProcess = ::GetCurrentProcess();
|
|
|
|
auto sym = reinterpret_cast<SYMBOL_INFOW*>(symbol_buf.data());
|
|
sym->SizeOfStruct = sizeof(SYMBOL_INFOW);
|
|
sym->MaxNameLen = 256;
|
|
|
|
IMAGEHLP_LINEW64 line_info{};
|
|
line_info.SizeOfStruct = sizeof(IMAGEHLP_LINEW64);
|
|
|
|
SymInitialize(hProcess, NULL, TRUE);
|
|
SymSetOptions(SYMOPT_LOAD_LINES);
|
|
|
|
for (const auto& pointer : stack)
|
|
{
|
|
DWORD64 unused;
|
|
SymFromAddrW(hProcess, reinterpret_cast<DWORD64>(pointer), &unused, sym);
|
|
|
|
if (sym->NameLen)
|
|
{
|
|
const auto function_name = wstr_to_utf8(sym->Name, static_cast<int>(sym->NameLen));
|
|
|
|
// Attempt to get file and line information if available
|
|
DWORD unused2;
|
|
if (SymGetLineFromAddrW64(hProcess, reinterpret_cast<DWORD64>(pointer), &unused2, &line_info))
|
|
{
|
|
const auto full_path = fmt::format("%s:%u %s", wstr_to_utf8(line_info.FileName, -1), line_info.LineNumber, function_name);
|
|
result.push_back(full_path);
|
|
}
|
|
else
|
|
{
|
|
result.push_back(function_name);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
result.push_back(fmt::format("rpcs3@0xp", pointer));
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
#else
|
|
std::vector<void*> get_backtrace(int max_depth)
|
|
{
|
|
std::vector<void*> result(max_depth);
|
|
int depth = backtrace(result.data(), max_depth);
|
|
|
|
result.resize(depth);
|
|
return result;
|
|
}
|
|
|
|
std::vector<std::string> get_backtrace_symbols(const std::vector<void*>& stack)
|
|
{
|
|
std::vector<std::string> result;
|
|
result.reserve(stack.size());
|
|
|
|
const auto symbols = backtrace_symbols(stack.data(), static_cast<int>(stack.size()));
|
|
for (usz i = 0; i < stack.size(); ++i)
|
|
{
|
|
result.push_back(symbols[i]);
|
|
}
|
|
|
|
free(symbols);
|
|
return result;
|
|
}
|
|
#endif
|
|
}
|