aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/cxx/include/aesnixx/debug.hpp
blob: 6c92a956be191e0c5eb9459d480ee0d64284e408 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/**
 * \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>
#pragma warning(push)
#pragma warning(disable: 4091)
#include <DbgHelp.h>
#pragma warning(pop)
#pragma comment(lib, "dbghelp.lib")
#endif

#include <cstddef>

#include <sstream>
#include <string>

namespace aesni
{
    namespace aux
    {
        class CallStackFormatter
        {
        public:
            CallStackFormatter()
            {
                #ifdef WIN32
                valid_flag = SymInitialize(GetCurrentProcess(), NULL, TRUE) ? true : false;
                #endif
            }

            std::string format(void* addr) const
            {
                #ifdef WIN32
                if (!valid_flag)
                    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 (valid_flag)
                    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 valid_flag = false;
            #endif
        };
    }
}