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 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
|
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/common/system_info.h>
#include <aws/common/byte_buf.h>
#include <aws/common/logging.h>
#include <aws/common/thread.h>
#include <windows.h>
enum aws_platform_os aws_get_platform_build_os(void) {
return AWS_PLATFORM_OS_WINDOWS;
}
size_t aws_system_info_processor_count(void) {
SYSTEM_INFO info;
GetSystemInfo(&info);
return info.dwNumberOfProcessors;
}
/* the next three functions need actual implementations before we can have proper numa alignment on windows.
* For now leave them stubbed out. */
uint16_t aws_get_cpu_group_count(void) {
return 1U;
}
size_t aws_get_cpu_count_for_group(uint16_t group_idx) {
(void)group_idx;
return aws_system_info_processor_count();
}
void aws_get_cpu_ids_for_group(uint16_t group_idx, struct aws_cpu_info *cpu_ids_array, size_t cpu_ids_array_length) {
(void)group_idx;
if (!cpu_ids_array_length) {
return;
}
/* a crude hint, but hyper-threads are numbered as the second half of the cpu id listing. */
size_t hyper_threads_hint = cpu_ids_array_length / 2 - 1;
for (size_t i = 0; i < cpu_ids_array_length; ++i) {
cpu_ids_array[i].cpu_id = (int32_t)i;
cpu_ids_array[i].suspected_hyper_thread = i > hyper_threads_hint;
}
}
bool aws_is_debugger_present(void) {
return IsDebuggerPresent();
}
void aws_debug_break(void) {
#ifdef DEBUG_BUILD
if (aws_is_debugger_present()) {
DebugBreak();
}
#endif
}
#if defined(AWS_OS_WINDOWS_DESKTOP)
/* If I meet the engineer that wrote the dbghelp.h file for the windows 8.1 SDK we're gonna have words! */
# ifdef _MSC_VER
# pragma warning(disable : 4091)
# endif
# include <dbghelp.h>
struct win_symbol_data {
struct _SYMBOL_INFO sym_info;
char symbol_name[1024];
};
typedef BOOL __stdcall SymInitialize_fn(_In_ HANDLE hProcess, _In_opt_ PCSTR UserSearchPath, _In_ BOOL fInvadeProcess);
typedef DWORD __stdcall SymSetOptions_fn(DWORD SymOptions);
typedef BOOL __stdcall SymFromAddr_fn(
_In_ HANDLE hProcess,
_In_ DWORD64 Address,
_Out_opt_ PDWORD64 Displacement,
_Inout_ PSYMBOL_INFO Symbol);
# if defined(_WIN64)
typedef BOOL __stdcall SymGetLineFromAddr_fn(
_In_ HANDLE hProcess,
_In_ DWORD64 qwAddr,
_Out_ PDWORD pdwDisplacement,
_Out_ PIMAGEHLP_LINE64 Line64);
# define SymGetLineFromAddrName "SymGetLineFromAddr64"
# else
typedef BOOL __stdcall SymGetLineFromAddr_fn(
_In_ HANDLE hProcess,
_In_ DWORD dwAddr,
_Out_ PDWORD pdwDisplacement,
_Out_ PIMAGEHLP_LINE Line);
# define SymGetLineFromAddrName "SymGetLineFromAddr"
# endif
static SymInitialize_fn *s_SymInitialize = NULL;
static SymSetOptions_fn *s_SymSetOptions = NULL;
static SymFromAddr_fn *s_SymFromAddr = NULL;
static SymGetLineFromAddr_fn *s_SymGetLineFromAddr = NULL;
static aws_thread_once s_init_once = AWS_THREAD_ONCE_STATIC_INIT;
static void s_init_dbghelp_impl(void *user_data) {
(void)user_data;
HMODULE dbghelp = LoadLibraryA("DbgHelp.dll");
if (!dbghelp) {
fprintf(stderr, "Failed to load DbgHelp.dll.\n");
goto done;
}
s_SymInitialize = (SymInitialize_fn *)GetProcAddress(dbghelp, "SymInitialize");
if (!s_SymInitialize) {
fprintf(stderr, "Failed to load SymInitialize from DbgHelp.dll.\n");
goto done;
}
s_SymSetOptions = (SymSetOptions_fn *)GetProcAddress(dbghelp, "SymSetOptions");
if (!s_SymSetOptions) {
fprintf(stderr, "Failed to load SymSetOptions from DbgHelp.dll\n");
goto done;
}
s_SymFromAddr = (SymFromAddr_fn *)GetProcAddress(dbghelp, "SymFromAddr");
if (!s_SymFromAddr) {
fprintf(stderr, "Failed to load SymFromAddr from DbgHelp.dll.\n");
goto done;
}
s_SymGetLineFromAddr = (SymGetLineFromAddr_fn *)GetProcAddress(dbghelp, SymGetLineFromAddrName);
if (!s_SymGetLineFromAddr) {
fprintf(stderr, "Failed to load " SymGetLineFromAddrName " from DbgHelp.dll.\n");
goto done;
}
HANDLE process = GetCurrentProcess();
AWS_FATAL_ASSERT(process);
s_SymInitialize(process, NULL, TRUE);
s_SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_ANYTHING | SYMOPT_LOAD_LINES);
return;
done:
if (dbghelp) {
FreeLibrary(dbghelp);
}
return;
}
static bool s_init_dbghelp() {
if (AWS_LIKELY(s_SymInitialize)) {
return true;
}
aws_thread_call_once(&s_init_once, s_init_dbghelp_impl, NULL);
return s_SymInitialize != NULL;
}
size_t aws_backtrace(void **stack_frames, size_t num_frames) {
return (int)CaptureStackBackTrace(0, (ULONG)num_frames, stack_frames, NULL);
}
char **aws_backtrace_symbols(void *const *stack_frames, size_t num_frames) {
if (!s_init_dbghelp()) {
return NULL;
}
struct aws_byte_buf symbols;
aws_byte_buf_init(&symbols, aws_default_allocator(), num_frames * 256);
/* pointers for each stack entry */
memset(symbols.buffer, 0, num_frames * sizeof(void *));
symbols.len += num_frames * sizeof(void *);
DWORD64 displacement = 0;
DWORD disp = 0;
struct aws_byte_cursor null_term = aws_byte_cursor_from_array("", 1);
HANDLE process = GetCurrentProcess();
AWS_FATAL_ASSERT(process);
for (size_t i = 0; i < num_frames; ++i) {
/* record a pointer to where the symbol will be */
*((char **)&symbols.buffer[i * sizeof(void *)]) = (char *)symbols.buffer + symbols.len;
uintptr_t address = (uintptr_t)stack_frames[i];
struct win_symbol_data sym_info;
AWS_ZERO_STRUCT(sym_info);
sym_info.sym_info.MaxNameLen = sizeof(sym_info.symbol_name);
sym_info.sym_info.SizeOfStruct = sizeof(struct _SYMBOL_INFO);
char sym_buf[1024]; /* scratch space for extracting info */
if (s_SymFromAddr(process, address, &displacement, &sym_info.sym_info)) {
/* record the address and name */
int len = snprintf(
sym_buf, AWS_ARRAY_SIZE(sym_buf), "at 0x%llX: %s", sym_info.sym_info.Address, sym_info.sym_info.Name);
if (len != -1) {
struct aws_byte_cursor symbol = aws_byte_cursor_from_array(sym_buf, len);
aws_byte_buf_append_dynamic(&symbols, &symbol);
}
IMAGEHLP_LINE line;
line.SizeOfStruct = sizeof(IMAGEHLP_LINE);
if (s_SymGetLineFromAddr(process, address, &disp, &line)) {
/* record file/line info */
len = snprintf(sym_buf, AWS_ARRAY_SIZE(sym_buf), "(%s:%lu)", line.FileName, line.LineNumber);
if (len != -1) {
struct aws_byte_cursor symbol = aws_byte_cursor_from_array(sym_buf, len);
aws_byte_buf_append_dynamic(&symbols, &symbol);
}
}
} else {
/* no luck, record the address and last error */
DWORD last_error = GetLastError();
int len = snprintf(
sym_buf,
AWS_ARRAY_SIZE(sym_buf),
"at 0x%p: Failed to lookup symbol: error %u",
stack_frames[i],
last_error);
if (len > 0) {
struct aws_byte_cursor sym_cur = aws_byte_cursor_from_array(sym_buf, len);
aws_byte_buf_append_dynamic(&symbols, &sym_cur);
}
}
/* Null terminator */
aws_byte_buf_append_dynamic(&symbols, &null_term);
}
return (char **)symbols.buffer; /* buffer must be freed by the caller */
}
char **aws_backtrace_addr2line(void *const *stack_frames, size_t stack_depth) {
return aws_backtrace_symbols(stack_frames, stack_depth);
}
void aws_backtrace_print(FILE *fp, void *call_site_data) {
struct _EXCEPTION_POINTERS *exception_pointers = call_site_data;
if (exception_pointers) {
fprintf(fp, "** Exception 0x%x occured **\n", exception_pointers->ExceptionRecord->ExceptionCode);
}
if (!s_init_dbghelp()) {
fprintf(fp, "Unable to initialize dbghelp.dll");
return;
}
void *stack[1024];
size_t num_frames = aws_backtrace(stack, 1024);
char **symbols = aws_backtrace_symbols(stack, num_frames);
for (size_t line = 0; line < num_frames; ++line) {
const char *symbol = symbols[line];
fprintf(fp, "%s\n", symbol);
}
fflush(fp);
aws_mem_release(aws_default_allocator(), symbols);
}
void aws_backtrace_log(int log_level) {
if (!s_init_dbghelp()) {
AWS_LOGF_ERROR(AWS_LS_COMMON_GENERAL, "Unable to initialize dbghelp.dll for backtrace");
return;
}
void *stack[1024];
size_t num_frames = aws_backtrace(stack, 1024);
char **symbols = aws_backtrace_symbols(stack, num_frames);
for (size_t line = 0; line < num_frames; ++line) {
const char *symbol = symbols[line];
AWS_LOGF(log_level, AWS_LS_COMMON_GENERAL, "%s", symbol);
}
aws_mem_release(aws_default_allocator(), symbols);
}
#else /* !AWS_OS_WINDOWS_DESKTOP */
size_t aws_backtrace(void **stack_frames, size_t num_frames) {
(void)stack_frames;
(void)num_frames;
return 0;
}
char **aws_backtrace_symbols(void *const *stack_frames, size_t stack_depth) {
(void)stack_frames;
(void)stack_depth;
return NULL;
}
char **aws_backtrace_addr2line(void *const *stack_frames, size_t stack_depth) {
return aws_backtrace_symbols(stack_frames, stack_depth);
}
void aws_backtrace_print(FILE *fp, void *call_site_data) {
(void)fp;
(void)call_site_data;
AWS_LOGF_TRACE(
AWS_LS_COMMON_GENERAL, "aws_backtrace_print: backtrace requested, but logging is unsupported on this platform");
}
void aws_backtrace_log() {
AWS_LOGF_TRACE(
AWS_LS_COMMON_GENERAL, "aws_backtrace_log: backtrace requested, but logging is unsupported on this platform");
}
#endif /* AWS_OS_WINDOWS_DESKTOP */
|