-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Expand file tree
/
Copy pathcompiler.cpp
More file actions
161 lines (120 loc) Β· 3.69 KB
/
Copy pathcompiler.cpp
File metadata and controls
161 lines (120 loc) Β· 3.69 KB
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
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
// Copyright 2015-2025 the openage authors. See copying.md for legal info.
#include "compiler.h"
#ifndef _WIN32
#include <cxxabi.h>
#include <dlfcn.h>
#else
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <DbgHelp.h>
#endif
#include "strings.h"
#include <array>
#include <iostream>
#include <mutex>
#include <optional>
namespace openage {
namespace util {
std::string demangle(const char *symbol) {
#ifdef _WIN32
// MSVC's typeid(T).name() already returns a demangled name
// unlike clang and gcc the MSVC demangled name is prefixed with "class " or "struct "
// we remove the prefix to match the format of clang and gcc
return strchr(symbol, ' ') + 1;
#else
int status;
char *buf = abi::__cxa_demangle(symbol, nullptr, nullptr, &status);
if (status != 0) {
return symbol;
}
else {
std::string result{buf};
free(buf);
return result;
}
#endif
}
std::string addr_to_string(const void *addr) {
return sformat("[%p]", addr);
}
#ifdef _WIN32
namespace {
bool initialized_symbol_handler_successfully = false;
std::optional<std::string> symbol_name_win(const void *addr) {
// Handle to the current process
static HANDLE process_handle = INVALID_HANDLE_VALUE;
static bool initialized_symbol_handler = false;
// SymInitialize & SymFromAddr are, according to MSDN, not thread-safe.
static std::mutex sym_mutex;
std::lock_guard<std::mutex> sym_lock_guard{sym_mutex};
// Initialize symbol handler for process, if it has not yet been initialized
// If we are not successful on the first try, leave it, since MSDN says that searching for symbol files is very time consuming
if (!initialized_symbol_handler) {
initialized_symbol_handler = true;
process_handle = GetCurrentProcess();
initialized_symbol_handler_successfully = SymInitialize(process_handle, nullptr, TRUE);
}
if (initialized_symbol_handler_successfully) {
// The magic of winapi
constexpr int name_buffer_size = 1024;
constexpr int buffer_size = sizeof(SYMBOL_INFO) + name_buffer_size * sizeof(char);
std::array<char, buffer_size> buffer;
SYMBOL_INFO *symbol_info = reinterpret_cast<SYMBOL_INFO *>(buffer.data());
symbol_info->SizeOfStruct = sizeof(SYMBOL_INFO);
symbol_info->MaxNameLen = name_buffer_size;
if (SymFromAddr(process_handle, reinterpret_cast<DWORD64>(addr), nullptr, symbol_info)) {
return std::string(symbol_info->Name);
}
}
return std::optional<std::string>();
}
} // namespace
#endif
std::string symbol_name(const void *addr, bool require_exact_addr, bool no_pure_addrs) {
#ifdef _WIN32
auto symbol_name_result = symbol_name_win(addr);
if (!initialized_symbol_handler_successfully || !symbol_name_result.has_value()) {
return no_pure_addrs ? "" : addr_to_string(addr);
}
return symbol_name_result.value();
#else
Dl_info addr_info;
if (dladdr(addr, &addr_info) == 0) {
// dladdr has... failed.
return no_pure_addrs ? "" : addr_to_string(addr);
}
else {
size_t symbol_offset = (size_t)addr - (size_t)addr_info.dli_saddr;
if (addr_info.dli_sname == nullptr or (symbol_offset != 0 and require_exact_addr)) {
return no_pure_addrs ? "" : addr_to_string(addr);
}
if (symbol_offset == 0) {
// this is our symbol name.
return demangle(addr_info.dli_sname);
}
else {
return util::sformat("%s+0x%lx",
demangle(addr_info.dli_sname).c_str(),
symbol_offset);
}
}
#endif
}
bool is_symbol(const void *addr) {
#ifdef _WIN32
if (!initialized_symbol_handler_successfully) {
return true;
}
else {
return symbol_name_win(addr).has_value();
}
#else
Dl_info addr_info;
if (dladdr(addr, &addr_info) == 0) {
return false;
}
return (addr_info.dli_saddr == addr);
#endif
}
} // namespace util
} // namespace openage