1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2024-11-21 18:22:33 +01:00

util: Provide stack-trace utilities

This commit is contained in:
kd-11 2022-08-14 03:36:53 +03:00 committed by kd-11
parent b960ce1426
commit 1244044647
5 changed files with 174 additions and 2 deletions

144
Utilities/stack_trace.cpp Normal file
View File

@ -0,0 +1,144 @@
#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*> backtrace(int max_depth)
{
std::vector<void*> result = {};
const auto hProcess = ::GetCurrentProcess();
const auto hThread = ::GetCurrentThread();
CONTEXT context{};
RtlCaptureContext(&context);
STACKFRAME64 stack = {};
stack.AddrPC.Offset = context.Rip;
stack.AddrPC.Mode = AddrModeFlat;
stack.AddrStack.Offset = context.Rsp;
stack.AddrStack.Mode = AddrModeFlat;
stack.AddrFrame.Offset = context.Rbp;
stack.AddrFrame.Mode = AddrModeFlat;
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> backtrace_symbols(const std::vector<void*>& stack)
{
std::vector<std::string> result = {};
std::vector<u8> symbol_buf(sizeof(SYMBOL_INFO) + sizeof(TCHAR) * 256);
const auto hProcess = ::GetCurrentProcess();
auto sym = reinterpret_cast<SYMBOL_INFO*>(symbol_buf.data());
sym->SizeOfStruct = sizeof(SYMBOL_INFO);
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;
SymFromAddr(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 (SymGetLineFromAddrW(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*> 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> 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
}

20
Utilities/stack_trace.h Normal file
View File

@ -0,0 +1,20 @@
#pragma once
#include <util/types.hpp>
#include <util/logs.hpp>
namespace utils
{
std::vector<void*> backtrace(int max_depth = 255);
std::vector<std::string> backtrace_symbols(const std::vector<void*>& stack);
FORCE_INLINE void print_trace(logs::channel& logger, int max_depth = 255)
{
const auto trace = backtrace(max_depth);
const auto lines = backtrace_symbols(trace);
for (const auto& line : lines)
{
logger.error("%s", line);
}
}
}

View File

@ -52,6 +52,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\Utilities\cheat_info.cpp" />
<ClCompile Include="..\Utilities\stack_trace.cpp" />
<ClCompile Include="Crypto\decrypt_binaries.cpp" />
<ClCompile Include="Emu\Audio\audio_resampler.cpp" />
<ClCompile Include="Emu\Audio\FAudio\FAudioBackend.cpp">
@ -458,6 +459,7 @@
<ClInclude Include="..\Utilities\address_range.h" />
<ClInclude Include="..\Utilities\cheat_info.h" />
<ClInclude Include="..\Utilities\simple_ringbuf.h" />
<ClInclude Include="..\Utilities\stack_trace.h" />
<ClInclude Include="..\Utilities\transactional_storage.h" />
<ClInclude Include="Crypto\decrypt_binaries.h" />
<ClInclude Include="Emu\Audio\audio_resampler.h" />

View File

@ -1090,6 +1090,9 @@
<ClCompile Include="Emu\Cell\Modules\cellMusicSelectionContext.cpp">
<Filter>Emu\Cell\Modules</Filter>
</ClCompile>
<ClCompile Include="..\Utilities\stack_trace.cpp">
<Filter>Utilities</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Crypto\aes.h">
@ -2173,6 +2176,9 @@
<ClInclude Include="Emu\Cell\Modules\cellMusicDecode.h">
<Filter>Emu\Cell\Modules</Filter>
</ClInclude>
<ClInclude Include="..\Utilities\stack_trace.h">
<Filter>Utilities</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="Emu\RSX\Program\GLSLSnippets\GPUDeswizzle.glsl">

View File

@ -88,7 +88,7 @@
<WarningLevel>Level3</WarningLevel>
</ClCompile>
<Link>
<AdditionalDependencies>Ole32.lib;gdi32.lib;..\hidapi.lib;..\libusb-1.0.lib;winmm.lib;ksuser.lib;OpenAL32.lib;XAudio.lib;GLGSRender.lib;shlwapi.lib;VKGSRender.lib;vulkan-1.lib;wolfssl.lib;libcurl.lib;Wldap32.lib;glslang.lib;OSDependent.lib;OGLCompiler.lib;SPIRV.lib;MachineIndependent.lib;GenericCodeGen.lib;Advapi32.lib;user32.lib;zlib.lib;..\libpng16.lib;asmjit.lib;yaml-cpp.lib;discord-rpc.lib;emucore.lib;dxgi.lib;$(QTDIR)\lib\qtmain.lib;shell32.lib;$(QTDIR)\lib\Qt5Widgets.lib;$(QTDIR)\lib\Qt5Gui.lib;$(QTDIR)\lib\Qt5Core.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib;Qt5WinExtras.lib;Qt5Concurrent.lib;7zlib.lib;SPIRV-Tools.lib;SPIRV-Tools-opt.lib;Qt5Multimedia.lib;Qt5MultimediaWidgets.lib;Qt5Svg.lib;libcubeb.lib;cubeb.lib;soundtouch.lib;Avrt.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>DbgHelp.lib;Ole32.lib;gdi32.lib;..\hidapi.lib;..\libusb-1.0.lib;winmm.lib;ksuser.lib;OpenAL32.lib;XAudio.lib;GLGSRender.lib;shlwapi.lib;VKGSRender.lib;vulkan-1.lib;wolfssl.lib;libcurl.lib;Wldap32.lib;glslang.lib;OSDependent.lib;OGLCompiler.lib;SPIRV.lib;MachineIndependent.lib;GenericCodeGen.lib;Advapi32.lib;user32.lib;zlib.lib;..\libpng16.lib;asmjit.lib;yaml-cpp.lib;discord-rpc.lib;emucore.lib;dxgi.lib;$(QTDIR)\lib\qtmain.lib;shell32.lib;$(QTDIR)\lib\Qt5Widgets.lib;$(QTDIR)\lib\Qt5Gui.lib;$(QTDIR)\lib\Qt5Core.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib;Qt5WinExtras.lib;Qt5Concurrent.lib;7zlib.lib;SPIRV-Tools.lib;SPIRV-Tools-opt.lib;Qt5Multimedia.lib;Qt5MultimediaWidgets.lib;Qt5Svg.lib;libcubeb.lib;cubeb.lib;soundtouch.lib;Avrt.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\3rdparty\OpenAL\libs\Win64;..\3rdparty\glslang\build\hlsl\Release;..\3rdparty\glslang\build\SPIRV\Release;..\3rdparty\glslang\build\OGLCompilersDLL\Release;..\3rdparty\glslang\build\glslang\OSDependent\Windows\Release;..\3rdparty\glslang\build\glslang\Release;..\3rdparty\SPIRV\build\source\Release;..\3rdparty\SPIRV\build\source\opt\Release;..\lib\$(CONFIGURATION)-$(PLATFORM);..\3rdparty\XAudio2Redist\libs;..\3rdparty\discord-rpc\lib;$(QTDIR)\lib;%(AdditionalLibraryDirectories);$(VULKAN_SDK)\Lib</AdditionalLibraryDirectories>
<AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" %(AdditionalOptions)</AdditionalOptions>
<DataExecutionPrevention>true</DataExecutionPrevention>
@ -139,7 +139,7 @@
<ProgramDataBaseFileName>$(IntDir)vc$(PlatformToolsetVersion).pdb</ProgramDataBaseFileName>
</ClCompile>
<Link>
<AdditionalDependencies>Ole32.lib;gdi32.lib;..\hidapi.lib;..\libusb-1.0.lib;winmm.lib;ksuser.lib;OpenAL32.lib;XAudio.lib;GLGSRender.lib;shlwapi.lib;VKGSRender.lib;vulkan-1.lib;wolfssl.lib;libcurl.lib;Wldap32.lib;glslangd.lib;OSDependentd.lib;OGLCompilerd.lib;SPIRVd.lib;MachineIndependentd.lib;GenericCodeGend.lib;Advapi32.lib;user32.lib;zlib.lib;..\libpng16.lib;asmjit.lib;yaml-cpp.lib;discord-rpc.lib;emucore.lib;dxgi.lib;$(QTDIR)\lib\qtmaind.lib;shell32.lib;$(QTDIR)\lib\Qt5Widgetsd.lib;$(QTDIR)\lib\Qt5Guid.lib;$(QTDIR)\lib\Qt5Cored.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib;Qt5WinExtrasd.lib;Qt5Concurrentd.lib;7zlib.lib;SPIRV-Tools.lib;SPIRV-Tools-opt.lib;Qt5Multimediad.lib;Qt5MultimediaWidgetsd.lib;Qt5Svgd.lib;libcubeb.lib;cubeb.lib;soundtouch.lib;Avrt.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalDependencies>DbgHelp.lib;Ole32.lib;gdi32.lib;..\hidapi.lib;..\libusb-1.0.lib;winmm.lib;ksuser.lib;OpenAL32.lib;XAudio.lib;GLGSRender.lib;shlwapi.lib;VKGSRender.lib;vulkan-1.lib;wolfssl.lib;libcurl.lib;Wldap32.lib;glslangd.lib;OSDependentd.lib;OGLCompilerd.lib;SPIRVd.lib;MachineIndependentd.lib;GenericCodeGend.lib;Advapi32.lib;user32.lib;zlib.lib;..\libpng16.lib;asmjit.lib;yaml-cpp.lib;discord-rpc.lib;emucore.lib;dxgi.lib;$(QTDIR)\lib\qtmaind.lib;shell32.lib;$(QTDIR)\lib\Qt5Widgetsd.lib;$(QTDIR)\lib\Qt5Guid.lib;$(QTDIR)\lib\Qt5Cored.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib;Qt5WinExtrasd.lib;Qt5Concurrentd.lib;7zlib.lib;SPIRV-Tools.lib;SPIRV-Tools-opt.lib;Qt5Multimediad.lib;Qt5MultimediaWidgetsd.lib;Qt5Svgd.lib;libcubeb.lib;cubeb.lib;soundtouch.lib;Avrt.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalLibraryDirectories>..\3rdparty\OpenAL\libs\Win64;..\3rdparty\glslang\build\hlsl\Debug;..\3rdparty\glslang\build\SPIRV\Debug;..\3rdparty\glslang\build\OGLCompilersDLL\Debug;..\3rdparty\glslang\build\glslang\OSDependent\Windows\Debug;..\3rdparty\glslang\build\glslang\Debug;..\3rdparty\SPIRV\build\source\opt\Debug;..\3rdparty\XAudio2Redist\libs;..\3rdparty\discord-rpc\lib;..\lib\$(CONFIGURATION)-$(PLATFORM);$(QTDIR)\lib;%(AdditionalLibraryDirectories);$(VULKAN_SDK)\Lib</AdditionalLibraryDirectories>
<AdditionalOptions>"/MANIFESTDEPENDENCY:type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' publicKeyToken='6595b64144ccf1df' language='*' processorArchitecture='*'" /VERBOSE %(AdditionalOptions)</AdditionalOptions>
<DataExecutionPrevention>true</DataExecutionPrevention>