MIRROR: javascript for ๐Ÿœ's, a tiny runtime with big ambitions
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

add windows crash handler

+154 -3
+2 -1
meson/deps/meson.build
··· 42 42 ws2_32_dep = cc.find_library('ws2_32', required: true) 43 43 iphlpapi_dep = cc.find_library('iphlpapi', required: true) 44 44 pathcch_dep = cc.find_library('pathcch', required: true) 45 - win_deps = [secur32_dep, ntdll_dep, crypt32_dep, userenv_dep, ws2_32_dep, iphlpapi_dep, pathcch_dep] 45 + dbghelp_dep = cc.find_library('dbghelp', required: true) 46 + win_deps = [secur32_dep, ntdll_dep, crypt32_dep, userenv_dep, ws2_32_dep, iphlpapi_dep, pathcch_dep, dbghelp_dep] 46 47 elif host_machine.system() == 'darwin' 47 48 security_dep = dependency('appleframeworks', modules: ['Security', 'CoreFoundation'], required: true) 48 49 win_deps = []
+152 -2
src/crash.c
··· 5 5 #include <stdint.h> 6 6 #include <stdlib.h> 7 7 #include <string.h> 8 - #include <unistd.h> 9 8 10 9 #ifndef _WIN32 11 10 #include <signal.h> 11 + #include <unistd.h> 12 12 13 13 #define ANT_CRASH_ALT_STACK_SIZE (64 * 1024) 14 14 ··· 142 142 143 143 #else // _WIN32 144 144 145 + #include <dbghelp.h> 146 + #include <process.h> 147 + 148 + static LPTOP_LEVEL_EXCEPTION_FILTER previous_filter; 149 + static volatile LONG crash_in_progress; 150 + 151 + static const char *exception_name(DWORD code) { 152 + switch (code) { 153 + case EXCEPTION_ACCESS_VIOLATION: return "EXCEPTION_ACCESS_VIOLATION"; 154 + case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: return "EXCEPTION_ARRAY_BOUNDS_EXCEEDED"; 155 + case EXCEPTION_BREAKPOINT: return "EXCEPTION_BREAKPOINT"; 156 + case EXCEPTION_DATATYPE_MISALIGNMENT: return "EXCEPTION_DATATYPE_MISALIGNMENT"; 157 + case EXCEPTION_FLT_DENORMAL_OPERAND: return "EXCEPTION_FLT_DENORMAL_OPERAND"; 158 + case EXCEPTION_FLT_DIVIDE_BY_ZERO: return "EXCEPTION_FLT_DIVIDE_BY_ZERO"; 159 + case EXCEPTION_FLT_INEXACT_RESULT: return "EXCEPTION_FLT_INEXACT_RESULT"; 160 + case EXCEPTION_FLT_INVALID_OPERATION: return "EXCEPTION_FLT_INVALID_OPERATION"; 161 + case EXCEPTION_FLT_OVERFLOW: return "EXCEPTION_FLT_OVERFLOW"; 162 + case EXCEPTION_FLT_STACK_CHECK: return "EXCEPTION_FLT_STACK_CHECK"; 163 + case EXCEPTION_FLT_UNDERFLOW: return "EXCEPTION_FLT_UNDERFLOW"; 164 + case EXCEPTION_ILLEGAL_INSTRUCTION: return "EXCEPTION_ILLEGAL_INSTRUCTION"; 165 + case EXCEPTION_IN_PAGE_ERROR: return "EXCEPTION_IN_PAGE_ERROR"; 166 + case EXCEPTION_INT_DIVIDE_BY_ZERO: return "EXCEPTION_INT_DIVIDE_BY_ZERO"; 167 + case EXCEPTION_INT_OVERFLOW: return "EXCEPTION_INT_OVERFLOW"; 168 + case EXCEPTION_INVALID_DISPOSITION: return "EXCEPTION_INVALID_DISPOSITION"; 169 + case EXCEPTION_NONCONTINUABLE_EXCEPTION: return "EXCEPTION_NONCONTINUABLE_EXCEPTION"; 170 + case EXCEPTION_PRIV_INSTRUCTION: return "EXCEPTION_PRIV_INSTRUCTION"; 171 + case EXCEPTION_STACK_OVERFLOW: return "EXCEPTION_STACK_OVERFLOW"; 172 + default: return "fatal exception"; 173 + }} 174 + 175 + static DWORD64 exception_fault_address(EXCEPTION_RECORD *record) { 176 + if (!record) return 0; 177 + if (( 178 + record->ExceptionCode == EXCEPTION_ACCESS_VIOLATION || 179 + record->ExceptionCode == EXCEPTION_IN_PAGE_ERROR) 180 + && record->NumberParameters >= 2 181 + ) return (DWORD64)record->ExceptionInformation[1]; 182 + return (DWORD64)(uintptr_t)record->ExceptionAddress; 183 + } 184 + 185 + static BOOL init_stack_frame(CONTEXT *ctx, STACKFRAME64 *frame, DWORD *machine) { 186 + memset(frame, 0, sizeof(*frame)); 187 + 188 + #if defined(_M_X64) || defined(__x86_64__) 189 + *machine = IMAGE_FILE_MACHINE_AMD64; 190 + frame->AddrPC.Offset = ctx->Rip; 191 + frame->AddrFrame.Offset = ctx->Rbp; 192 + frame->AddrStack.Offset = ctx->Rsp; 193 + #elif defined(_M_IX86) || defined(__i386__) 194 + *machine = IMAGE_FILE_MACHINE_I386; 195 + frame->AddrPC.Offset = ctx->Eip; 196 + frame->AddrFrame.Offset = ctx->Ebp; 197 + frame->AddrStack.Offset = ctx->Esp; 198 + #elif defined(_M_ARM64) || defined(__aarch64__) 199 + *machine = IMAGE_FILE_MACHINE_ARM64; 200 + frame->AddrPC.Offset = ctx->Pc; 201 + frame->AddrFrame.Offset = ctx->Fp; 202 + frame->AddrStack.Offset = ctx->Sp; 203 + #else 204 + return FALSE; 205 + #endif 206 + frame->AddrPC.Mode = AddrModeFlat; 207 + frame->AddrFrame.Mode = AddrModeFlat; 208 + frame->AddrStack.Mode = AddrModeFlat; 209 + return TRUE; 210 + } 211 + 212 + static void print_windows_backtrace(EXCEPTION_POINTERS *exc) { 213 + if (!exc || !exc->ContextRecord) { 214 + fprintf(stderr, " (no exception context available)\n"); 215 + return; 216 + } 217 + 218 + HANDLE process = GetCurrentProcess(); 219 + HANDLE thread = GetCurrentThread(); 220 + 221 + SymSetOptions(SYMOPT_DEFERRED_LOADS | SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); 222 + if (!SymInitialize(process, NULL, TRUE)) { 223 + fprintf(stderr, " (SymInitialize failed: %lu)\n", GetLastError()); 224 + return; 225 + } 226 + 227 + CONTEXT ctx = *exc->ContextRecord; 228 + STACKFRAME64 frame; 229 + DWORD machine; 230 + if (!init_stack_frame(&ctx, &frame, &machine)) { 231 + fprintf(stderr, " (unsupported Windows architecture for StackWalk64)\n"); 232 + return; 233 + } 234 + 235 + union { 236 + SYMBOL_INFO info; 237 + char storage[sizeof(SYMBOL_INFO) + MAX_SYM_NAME]; 238 + } symbol_buf; 239 + 240 + SYMBOL_INFO *symbol = &symbol_buf.info; 241 + memset(&symbol_buf, 0, sizeof(symbol_buf)); 242 + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); 243 + symbol->MaxNameLen = MAX_SYM_NAME; 244 + 245 + for (int i = 0; i < 64; i++) { 246 + DWORD64 addr = frame.AddrPC.Offset; 247 + if (addr == 0) break; 248 + DWORD64 displacement = 0; 249 + 250 + fprintf(stderr, "%d 0x%016llx", i, (unsigned long long)addr); 251 + if (SymFromAddr(process, addr, &displacement, symbol)) 252 + fprintf(stderr, " %s + %llu", symbol->Name, (unsigned long long)displacement); 253 + 254 + IMAGEHLP_LINE64 line; 255 + DWORD line_disp = 0; 256 + memset(&line, 0, sizeof(line)); 257 + line.SizeOfStruct = sizeof(line); 258 + if (SymGetLineFromAddr64(process, addr, &line_disp, &line)) 259 + fprintf(stderr, " (%s:%lu)", line.FileName, line.LineNumber); 260 + 261 + fputc('\n', stderr); 262 + DWORD64 prev_pc = frame.AddrPC.Offset; 263 + DWORD64 prev_sp = frame.AddrStack.Offset; 264 + BOOL ok = StackWalk64( 265 + machine, process, thread, &frame, &ctx, NULL, 266 + SymFunctionTableAccess64, SymGetModuleBase64, NULL 267 + ); 268 + if (!ok || (frame.AddrPC.Offset == prev_pc && frame.AddrStack.Offset == prev_sp)) break; 269 + } 270 + } 271 + 272 + static LONG WINAPI windows_crash_handler(EXCEPTION_POINTERS *exc) { 273 + if (InterlockedExchange(&crash_in_progress, 1) != 0) { 274 + return EXCEPTION_CONTINUE_SEARCH; 275 + } 276 + 277 + EXCEPTION_RECORD *record = exc ? exc->ExceptionRecord : NULL; 278 + DWORD code = record ? record->ExceptionCode : 0; 279 + 280 + fprintf(stderr, "\n=== ant crashed: %s (0x%08lx) ===\n", exception_name(code), (unsigned long)code); 281 + fprintf(stderr, " fault address: 0x%016llx\n", (unsigned long long)exception_fault_address(record)); 282 + fprintf(stderr, " ant version: " ANT_VERSION "\n"); 283 + fprintf(stderr, " pid: %lu\n\n", (unsigned long)_getpid()); 284 + fprintf(stderr, "Native backtrace:\n"); 285 + print_windows_backtrace(exc); 286 + 287 + fprintf(stderr, 288 + "\nPlease report this at https://github.com/themackabu/ant/issues\n" 289 + "Include the backtrace above and a minimal reproducer if possible.\n\n"); 290 + 291 + if (previous_filter) return previous_filter(exc); 292 + return EXCEPTION_EXECUTE_HANDLER; 293 + } 294 + 145 295 void ant_crash_init(void) { 146 - // TODO: SetUnhandledExceptionFilter + StackWalk64 / dbghelp 296 + previous_filter = SetUnhandledExceptionFilter(windows_crash_handler); 147 297 } 148 298 149 299 #endif