aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/cxx
diff options
context:
space:
mode:
Diffstat (limited to 'cxx')
-rw-r--r--cxx/include/aesnixx/all.hpp1
-rw-r--r--cxx/include/aesnixx/debug.hpp123
-rw-r--r--cxx/include/aesnixx/error.hpp61
3 files changed, 179 insertions, 6 deletions
diff --git a/cxx/include/aesnixx/all.hpp b/cxx/include/aesnixx/all.hpp
index 72ea262..1452f68 100644
--- a/cxx/include/aesnixx/all.hpp
+++ b/cxx/include/aesnixx/all.hpp
@@ -10,4 +10,5 @@
#include "aes.hpp"
#include "data.hpp"
+#include "debug.hpp"
#include "error.hpp"
diff --git a/cxx/include/aesnixx/debug.hpp b/cxx/include/aesnixx/debug.hpp
new file mode 100644
index 0000000..f87942d
--- /dev/null
+++ b/cxx/include/aesnixx/debug.hpp
@@ -0,0 +1,123 @@
+/**
+ * \file
+ * \author Egor Tensin <Egor.Tensin@gmail.com>
+ * \date 2015
+ * \copyright This file is licensed under the terms of the MIT License.
+ * See LICENSE.txt for details.
+ */
+
+#pragma once
+
+#ifdef WIN32
+#include <Windows.h>
+#include <DbgHelp.h>
+#pragma comment(lib, "dbghelp.lib")
+#endif
+
+#include <cstddef>
+
+#include <sstream>
+#include <string>
+
+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<DWORD64>(addr), &displacement_within_symbol, symbol_info))
+ {
+ if (!SymGetModuleInfo64(GetCurrentProcess(), reinterpret_cast<DWORD64>(addr), &module_info))
+ return format_fallback(addr);
+
+ void* const displacement_within_module = reinterpret_cast<char*>(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<void*>(displacement_within_symbol));
+ #else
+ return format_fallback(addr);
+ #endif
+ }
+
+ ~CallStackFormatter()
+ {
+ #ifdef WIN32
+ if (m_valid)
+ SymCleanup(GetCurrentProcess());
+ #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();
+ }
+
+ 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
+ };
+ }
+}
diff --git a/cxx/include/aesnixx/error.hpp b/cxx/include/aesnixx/error.hpp
index 4c1fc98..013e2ef 100644
--- a/cxx/include/aesnixx/error.hpp
+++ b/cxx/include/aesnixx/error.hpp
@@ -8,16 +8,70 @@
#pragma once
+#include "debug.hpp"
+
#include <aesni/all.h>
#include <cstdlib>
+#include <cstring>
+#include <algorithm>
+#include <functional>
+#include <ostream>
#include <stdexcept>
#include <string>
#include <vector>
namespace aesni
{
+ class Error : public std::runtime_error
+ {
+ public:
+ Error(const AesNI_ErrorDetails& err_details)
+ : std::runtime_error(format_error_message(err_details))
+ {
+ copy_call_stack(err_details);
+ }
+
+ void for_each_in_call_stack(const std::function<void (void*, const std::string&)>& callback) const
+ {
+ aux::CallStackFormatter formatter;
+ std::for_each(m_call_stack, m_call_stack + m_call_stack_size, [&formatter, &callback] (void* addr)
+ {
+ callback(addr, formatter.format(addr));
+ });
+ }
+
+ private:
+ static std::string format_error_message(const AesNI_ErrorDetails& err_details)
+ {
+ std::vector<char> buf;
+ buf.resize(aesni_format_error(&err_details, NULL, 0));
+ aesni_format_error(&err_details, buf.data(), buf.size());
+ return { buf.begin(), buf.end() };
+ }
+
+ void copy_call_stack(const AesNI_ErrorDetails& err_details)
+ {
+ m_call_stack_size = err_details.call_stack_size;
+ std::memcpy(m_call_stack, err_details.call_stack, m_call_stack_size * sizeof(void*));
+ }
+
+ void* m_call_stack[AESNI_MAX_CALL_STACK_LENGTH];
+ std::size_t m_call_stack_size;
+ };
+
+ std::ostream& operator<<(std::ostream& os, const Error& e)
+ {
+ os << "AesNI error: " << e.what() << '\n';
+ os << "Call stack:\n";
+ e.for_each_in_call_stack([&os] (void* addr, const std::string& name)
+ {
+ os << '\t' << addr << ' ' << name << '\n';
+ });
+ return os;
+ }
+
class ErrorDetailsThrowsInDestructor
{
public:
@@ -29,12 +83,7 @@ namespace aesni
~ErrorDetailsThrowsInDestructor()
{
if (aesni_is_error(aesni_get_error_code(get())))
- {
- std::vector<char> msg;
- msg.resize(aesni_format_error(get(), NULL, 0));
- aesni_format_error(get(), msg.data(), msg.size());
- throw std::runtime_error(std::string(msg.begin(), msg.end()));
- }
+ throw Error(m_impl);
}
AesNI_ErrorDetails* get() { return &m_impl; }