diff options
Diffstat (limited to 'aesxx/include/aesxx/debug.hpp')
-rw-r--r-- | aesxx/include/aesxx/debug.hpp | 174 |
1 files changed, 174 insertions, 0 deletions
diff --git a/aesxx/include/aesxx/debug.hpp b/aesxx/include/aesxx/debug.hpp new file mode 100644 index 0000000..96e81b5 --- /dev/null +++ b/aesxx/include/aesxx/debug.hpp @@ -0,0 +1,174 @@ +// Copyright (c) 2015 Egor Tensin <Egor.Tensin@gmail.com> +// This file is part of the "AES tools" project. +// For details, see https://github.com/egor-tensin/aes-tools. +// Distributed under the MIT License. + +#pragma once + +#ifdef WIN32 +#include <windows.h> +#include <DbgHelp.h> +#pragma comment(lib, "DbgHelp.Lib") +#endif + +#include <cstddef> + +#include <sstream> +#include <string> + +namespace aes +{ + namespace aux + { + class CallStackFormatter + { + public: + CallStackFormatter() = default; + + std::string format_address(const void* addr) const + { + #ifdef WIN32 + return format_address_win32(addr); + #else + return format_address_fallback(addr); + #endif + } + + private: + template <typename T> + static std::string put_between_brackets(const T& x) + { + std::ostringstream oss; + oss << "[" << x << "]"; + return oss.str(); + } + + template <typename T> + static std::string stringify(const T& x) + { + std::ostringstream oss; + oss << x; + return oss.str(); + } + + static std::string format_address_fallback(const void* addr) + { + return put_between_brackets(addr); + } + + static std::string format_module( + const std::string& module_name, + const void* offset = nullptr) + { + if (offset == nullptr) + return put_between_brackets(module_name); + else + return put_between_brackets(module_name + "+" + stringify(offset)); + } + + static std::string format_symbol( + const std::string& symbol_name, + const void* offset = nullptr) + { + return format_module(symbol_name, offset); + } + + static std::string format_symbol( + const std::string& module_name, + const std::string& symbol_name, + const void* offset = nullptr) + { + return format_symbol(module_name + "!" + symbol_name, offset); + } + + #ifdef WIN32 + class DbgHelp + { + public: + DbgHelp() + { + initialized_flag = SymInitialize(GetCurrentProcess(), NULL, TRUE) != FALSE; + } + + bool initialized() const + { + return initialized_flag; + } + + ~DbgHelp() + { + if (initialized_flag) + SymCleanup(GetCurrentProcess()); + } + + private: + bool initialized_flag = false; + + DbgHelp(const DbgHelp&) = delete; + DbgHelp& operator=(const DbgHelp&) = delete; + }; + + DbgHelp dbghelp; + + std::string format_address_win32(const void* addr) const + { + if (!dbghelp.initialized()) + return format_address_fallback(addr); + + DWORD64 symbol_info_buf[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; + const auto symbol_info = reinterpret_cast<SYMBOL_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 symbol_offset; + + const auto symbol_resolved = SymFromAddr( + GetCurrentProcess(), + reinterpret_cast<DWORD64>(addr), + &symbol_offset, + symbol_info); + + if (symbol_resolved) + { + const auto module_resolved = SymGetModuleInfo64( + GetCurrentProcess(), + symbol_info->ModBase, + &module_info); + + if (module_resolved) + { + return format_symbol( + module_info.ModuleName, + symbol_info->Name, + reinterpret_cast<const void*>(symbol_offset)); + } + else + { + return format_symbol(symbol_info->Name, addr); + } + } + else + { + const auto module_resolved = SymGetModuleInfo64( + GetCurrentProcess(), + reinterpret_cast<DWORD64>(addr), + &module_info); + + if (module_resolved) + { + const auto module_offset = reinterpret_cast<const char*>(addr) - module_info.BaseOfImage; + return format_module(module_info.ModuleName, module_offset); + } + else + { + return format_address_fallback(addr); + } + } + } + #endif + }; + } +} |