/** * \file * \author Egor Tensin * \date 2015 * \copyright This file is licensed under the terms of the MIT License. * See LICENSE.txt for details. */ #pragma once #ifdef WIN32 #include #pragma warning(push) #pragma warning(disable: 4091) #include #pragma warning(pop) #pragma comment(lib, "dbghelp.lib") #endif #include #include #include namespace aesni { namespace aux { class CallStackFormatter { public: CallStackFormatter() { #ifdef WIN32 m_valid = SymInitialize(GetCurrentProcess(), NULL, TRUE) ? true : false; #endif } std::string format(void* addr) const { #ifdef WIN32 if (!m_valid) return format_fallback(addr); DWORD64 symbol_info_buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; PSYMBOL_INFO symbol_info = (PSYMBOL_INFO) symbol_info_buf; symbol_info->SizeOfStruct = sizeof(SYMBOL_INFO); symbol_info->MaxNameLen = MAX_SYM_NAME; IMAGEHLP_MODULE64 module_info; module_info.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); DWORD64 displacement_within_symbol; if (!SymFromAddr(GetCurrentProcess(), reinterpret_cast(addr), &displacement_within_symbol, symbol_info)) { if (!SymGetModuleInfo64(GetCurrentProcess(), reinterpret_cast(addr), &module_info)) return format_fallback(addr); void* const displacement_within_module = reinterpret_cast(addr) - module_info.BaseOfImage; return format_with_module(module_info.ModuleName, displacement_within_module); } if (!SymGetModuleInfo64(GetCurrentProcess(), symbol_info->ModBase, &module_info)) return format_with_symbol(symbol_info->Name, addr); return format_with_symbol_and_module(symbol_info->Name, module_info.ModuleName, reinterpret_cast(displacement_within_symbol)); #else return format_fallback(addr); #endif } ~CallStackFormatter() { #ifdef WIN32 if (m_valid) SymCleanup(GetCurrentProcess()); #endif } private: template static std::string put_between_brackets(const T& x) { std::ostringstream oss; oss << "[" << x << "]"; return oss.str(); } template static std::string stringify(const T& x) { std::ostringstream oss; oss << x; return oss.str(); } std::string format_fallback(void* addr) const { return put_between_brackets(addr); } std::string format_with_module(const std::string& module_name, void* displacement) const { if (displacement == NULL) return put_between_brackets(module_name); else return put_between_brackets(module_name + "+" + stringify(displacement)); } std::string format_with_symbol(const std::string& symbol_name, void* displacement) const { return format_with_module(symbol_name, displacement); } std::string format_with_symbol_and_module(const std::string& symbol_name, const std::string& module_name, void* displacement) const { return format_with_symbol(module_name + "!" + symbol_name, displacement); } #ifdef WIN32 bool m_valid = false; #endif }; } }