File: system_info.c

package info (click to toggle)
aws-crt-python 0.20.4%2Bdfsg-1~bpo12%2B1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm-backports
  • size: 72,656 kB
  • sloc: ansic: 381,805; python: 23,008; makefile: 6,251; sh: 4,536; cpp: 699; ruby: 208; java: 77; perl: 73; javascript: 46; xml: 11
file content (303 lines) | stat: -rw-r--r-- 9,980 bytes parent folder | download | duplicates (2)
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 */