aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/aesxx/include/aesxx/debug.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'aesxx/include/aesxx/debug.hpp')
-rw-r--r--aesxx/include/aesxx/debug.hpp174
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
+ };
+ }
+}