unrealircd- supernets unrealircd source & configuration |
git clone git://git.acid.vegas/unrealircd.git |
Log | Files | Refs | Archive | README | LICENSE |
windebug.c (11196B)
1 /************************************************************************ 2 * IRC - Internet Relay Chat, windows/windebug.c 3 * Copyright (C) 2002-2004 Dominick Meglio (codemastr) 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 1, or (at your option) 8 * any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18 */ 19 20 #include "unrealircd.h" 21 #include <dbghelp.h> 22 23 #ifndef IRCDTOTALVERSION 24 #define IRCDTOTALVERSION BASE_VERSION "-" PATCH1 PATCH2 PATCH3 PATCH4 PATCH5 PATCH6 PATCH7 PATCH8 PATCH9 25 #endif 26 27 extern OSVERSIONINFO VerInfo; 28 extern char OSName[256]; 29 extern char backupbuf[8192]; 30 extern char *buildid; 31 extern char *extraflags; 32 33 /* crappy, but safe :p */ 34 typedef BOOL (WINAPI *MINIDUMPWRITEDUMP)(HANDLE hProcess, DWORD dwPid, HANDLE hFile, MINIDUMP_TYPE DumpType, 35 CONST PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam, 36 CONST PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam, 37 CONST PMINIDUMP_CALLBACK_INFORMATION CallbackParam 38 ); 39 40 41 /* Runs a stack trace 42 * Parameters: 43 * e - The exception information 44 * Returns: 45 * The stack trace with function and line number information 46 */ 47 __inline char *StackTrace(EXCEPTION_POINTERS *e) 48 { 49 static char buffer[5000]; 50 char curmodule[256]; 51 DWORD symOptions; 52 DWORD64 dwDisp; 53 DWORD dwDisp32; 54 int frame; 55 HANDLE hProcess = GetCurrentProcess(); 56 IMAGEHLP_SYMBOL64 *pSym = safe_alloc(sizeof(IMAGEHLP_SYMBOL64)+500); 57 IMAGEHLP_LINE64 pLine; 58 IMAGEHLP_MODULE64 pMod; 59 STACKFRAME64 Stack; 60 CONTEXT context; 61 62 memcpy(&context, e->ContextRecord, sizeof(CONTEXT)); 63 64 /* Load the stack information */ 65 memset(&Stack, 0, sizeof(Stack)); 66 Stack.AddrPC.Offset = e->ContextRecord->Rip; 67 Stack.AddrPC.Mode = AddrModeFlat; 68 Stack.AddrFrame.Offset = e->ContextRecord->Rbp; 69 Stack.AddrFrame.Mode = AddrModeFlat; 70 Stack.AddrStack.Offset = e->ContextRecord->Rsp; 71 Stack.AddrStack.Mode = AddrModeFlat; 72 hProcess = GetCurrentProcess(); 73 74 /* Initialize symbol retrieval system */ 75 SymInitialize(hProcess, NULL, TRUE); 76 SymSetOptions(SYMOPT_LOAD_LINES|SYMOPT_UNDNAME); 77 pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); 78 pSym->MaxNameLength = 500; 79 80 /* Retrieve the first module name */ 81 memset(&pMod, 0, sizeof(pMod)); 82 pMod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); 83 SymGetModuleInfo64(hProcess, Stack.AddrPC.Offset, &pMod); 84 strcpy(curmodule, pMod.ModuleName); 85 sprintf(buffer, "\tModule: %s\n", pMod.ModuleName); 86 87 /* Walk through the stack */ 88 for (frame = 0; ; frame++) 89 { 90 char buf[500]; 91 if (!StackWalk64(IMAGE_FILE_MACHINE_AMD64, GetCurrentProcess(), GetCurrentThread(), 92 &Stack, &context, NULL, SymFunctionTableAccess64, SymGetModuleBase64, NULL)) 93 break; 94 95 memset(&pMod, 0, sizeof(pMod)); 96 pMod.SizeOfStruct = sizeof(IMAGEHLP_MODULE64); 97 SymGetModuleInfo64(hProcess, Stack.AddrPC.Offset, &pMod); 98 if (strcmp(curmodule, pMod.ModuleName)) 99 { 100 strcpy(curmodule, pMod.ModuleName); 101 sprintf(buf, "\tModule: %s\n", pMod.ModuleName); 102 strcat(buffer, buf); 103 } 104 105 memset(&pLine, 0, sizeof(pLine)); 106 pLine.SizeOfStruct = sizeof(IMAGEHLP_LINE64); 107 SymGetLineFromAddr64(hProcess, Stack.AddrPC.Offset, &dwDisp32, &pLine); 108 SymGetSymFromAddr64(hProcess, Stack.AddrPC.Offset, &dwDisp, pSym); 109 sprintf(buf, "\t\t#%d %s:%d: %s\n", frame, pLine.FileName, pLine.LineNumber, 110 pSym->Name); 111 strcat(buffer, buf); 112 } 113 strcat(buffer, "End of Stack trace\n"); 114 return buffer; 115 116 } 117 118 /* Retrieves the values of several registers 119 * Parameters: 120 * context - The CPU context 121 * Returns: 122 * The values of the registers as a string. 123 */ 124 __inline char *GetRegisters(CONTEXT *context) 125 { 126 static char buffer[1024]; 127 128 sprintf(buffer, 129 "\tRAX=%p" 130 "\tRBX=%p" 131 "\tRCX=%p" 132 "\tRDX=%p\n" 133 "\tRSI=%p" 134 "\tRDI=%p" 135 "\tRBP=%p" 136 "\tRSP=%p\n" 137 "\tR8=%p" 138 "\tR9=%p" 139 "\tR10=%p" 140 "\tR11=%p\n" 141 "\tR12=%p" 142 "\tR13=%p" 143 "\tR14=%p" 144 "\tR15=%p\n" 145 "\tRIP=%p\n", 146 (void *)context->Rax, 147 (void *)context->Rbx, 148 (void *)context->Rcx, 149 (void *)context->Rdx, 150 (void *)context->Rsi, 151 (void *)context->Rdi, 152 (void *)context->Rbp, 153 (void *)context->Rsp, 154 (void *)context->R8, 155 (void *)context->R9, 156 (void *)context->R10, 157 (void *)context->R11, 158 (void *)context->R12, 159 (void *)context->R13, 160 (void *)context->R14, 161 (void *)context->R15, 162 (void *)context->Rip); 163 164 return buffer; 165 } 166 167 /* Convert the exception code to a human readable string 168 * Parameters: 169 * code - The exception code to convert 170 * Returns: 171 * The exception code represented as a string 172 */ 173 __inline char *GetException(DWORD code) 174 { 175 switch (code) 176 { 177 case EXCEPTION_ACCESS_VIOLATION: 178 return "Access Violation"; 179 case EXCEPTION_ARRAY_BOUNDS_EXCEEDED: 180 return "Array Bounds Exceeded"; 181 case EXCEPTION_BREAKPOINT: 182 return "Breakpoint"; 183 case EXCEPTION_DATATYPE_MISALIGNMENT: 184 return "Datatype Misalignment"; 185 case EXCEPTION_FLT_DENORMAL_OPERAND: 186 return "Floating Point Denormal Operand"; 187 case EXCEPTION_FLT_DIVIDE_BY_ZERO: 188 return "Floating Point Division By Zero"; 189 case EXCEPTION_FLT_INEXACT_RESULT: 190 return "Floating Point Inexact Result"; 191 case EXCEPTION_FLT_INVALID_OPERATION: 192 return "Floating Point Invalid Operation"; 193 case EXCEPTION_FLT_OVERFLOW: 194 return "Floating Point Overflow"; 195 case EXCEPTION_FLT_STACK_CHECK: 196 return "Floating Point Stack Overflow"; 197 case EXCEPTION_FLT_UNDERFLOW: 198 return "Floating Point Underflow"; 199 case EXCEPTION_ILLEGAL_INSTRUCTION: 200 return "Illegal Instruction"; 201 case EXCEPTION_IN_PAGE_ERROR: 202 return "In Page Error"; 203 case EXCEPTION_INT_DIVIDE_BY_ZERO: 204 return "Integer Division By Zero"; 205 case EXCEPTION_INT_OVERFLOW: 206 return "Integer Overflow"; 207 case EXCEPTION_INVALID_DISPOSITION: 208 return "Invalid Disposition"; 209 case EXCEPTION_NONCONTINUABLE_EXCEPTION: 210 return "Noncontinuable Exception"; 211 case EXCEPTION_PRIV_INSTRUCTION: 212 return "Unallowed Instruction"; 213 case EXCEPTION_SINGLE_STEP: 214 return "Single Step"; 215 case EXCEPTION_STACK_OVERFLOW: 216 return "Stack Overflow"; 217 default: 218 return "Unknown Exception"; 219 } 220 } 221 222 void StartCrashReporter(void) 223 { 224 char fname[MAX_PATH], fnamewarg[MAX_PATH+32]; 225 PROCESS_INFORMATION pi; 226 STARTUPINFO si; 227 228 memset(&pi, 0, sizeof(pi)); 229 memset(&si, 0, sizeof(si)); 230 231 GetModuleFileName(GetModuleHandle(NULL), fname, MAX_PATH); 232 233 snprintf(fnamewarg, sizeof(fnamewarg), "\"%s\" %s", fname, "-R"); 234 CreateProcess(fname, fnamewarg, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); 235 } 236 237 void StartUnrealAgain(void) 238 { 239 char fname[MAX_PATH], fnamewarg[MAX_PATH+32]; 240 PROCESS_INFORMATION pi; 241 STARTUPINFO si; 242 243 memset(&pi, 0, sizeof(pi)); 244 memset(&si, 0, sizeof(si)); 245 246 GetModuleFileName(GetModuleHandle(NULL), fname, MAX_PATH); 247 248 snprintf(fnamewarg, sizeof(fnamewarg), "\"%s\"", fname); 249 CreateProcess(fname, NULL, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); 250 } 251 252 /* Callback for the exception handler 253 * Parameters: 254 * e - The exception information 255 * Returns: 256 * EXCEPTION_EXECUTE_HANDLER to terminate the process 257 * Side Effects: 258 * unrealircd.PID.core is created 259 * If not running in service mode, a message box is displayed, 260 * else output is written to service.log 261 */ 262 LONG __stdcall ExceptionFilter(EXCEPTION_POINTERS *e) 263 { 264 MEMORYSTATUSEX memStats; 265 char file[512], text[1024], minidumpf[512]; 266 FILE *fd; 267 time_t timet = time(NULL); 268 #ifndef NOMINIDUMP 269 HANDLE hDump; 270 HMODULE hDll = NULL; 271 #endif 272 273 sprintf(file, "unrealircd.%d.core", getpid()); 274 fd = fopen(file, "w"); 275 GlobalMemoryStatusEx(&memStats); 276 fprintf(fd, "Generated at %s\nOS: %s\n%s[%s%s%s] (%s) on %s\n" 277 "-----------------\nMemory Information:\n" 278 "\tPhysical: (Available:%lluMB/Total:%lluMB)\n" 279 "\tVirtual: (Available:%lluMB/Total:%lluMB)\n" 280 "-----------------\nException:\n\t%s\n-----------------\n" 281 "Backup Buffer:\n\t%s\n-----------------\nRegisters:\n" 282 "%s-----------------\nStack Trace:\n%s", 283 asctime(gmtime(&timet)), OSName, 284 IRCDTOTALVERSION, 285 serveropts, extraflags ? extraflags : "", tainted ? "3" : "", 286 buildid, me.name, memStats.ullAvailPhys/1048576, memStats.ullTotalPhys/1048576, 287 memStats.ullAvailVirtual/1048576, memStats.ullTotalVirtual/1048576, 288 GetException(e->ExceptionRecord->ExceptionCode), backupbuf, 289 GetRegisters(e->ContextRecord), StackTrace(e)); 290 291 sprintf(text, "UnrealIRCd has encountered a fatal error. Debugging information has been dumped to %s.", file); 292 fclose(fd); 293 294 #ifndef NOMINIDUMP 295 hDll = LoadLibrary("DBGHELP.DLL"); 296 if (hDll) 297 { 298 MINIDUMPWRITEDUMP pDump = (MINIDUMPWRITEDUMP)GetProcAddress(hDll, "MiniDumpWriteDump"); 299 if (pDump) 300 { 301 MINIDUMP_EXCEPTION_INFORMATION ExInfo; 302 sprintf(minidumpf, "unrealircd.%d.mdmp", getpid()); 303 hDump = CreateFile(minidumpf, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 304 if (hDump != INVALID_HANDLE_VALUE) 305 { 306 ExInfo.ThreadId = GetCurrentThreadId(); 307 ExInfo.ExceptionPointers = e; 308 ExInfo.ClientPointers = 0; 309 310 if (pDump(GetCurrentProcess(), GetCurrentProcessId(), hDump, MiniDumpWithIndirectlyReferencedMemory, &ExInfo, NULL, NULL)) 311 { 312 sprintf(text, "UnrealIRCd has encountered a fatal error. Debugging information has been dumped to %s and %s.", file, minidumpf); 313 } 314 CloseHandle(hDump); 315 } 316 sprintf(minidumpf, "unrealircd.%d.full.mdmp", getpid()); 317 hDump = CreateFile(minidumpf, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); 318 if (hDump != INVALID_HANDLE_VALUE) 319 { 320 ExInfo.ThreadId = GetCurrentThreadId(); 321 ExInfo.ExceptionPointers = e; 322 ExInfo.ClientPointers = 0; 323 324 pDump(GetCurrentProcess(), GetCurrentProcessId(), hDump, MiniDumpWithPrivateReadWriteMemory, &ExInfo, NULL, NULL); 325 CloseHandle(hDump); 326 } 327 } 328 } 329 #endif 330 331 if (!IsService) 332 { 333 MessageBox(NULL, text, "Fatal Error", MB_OK); 334 StartCrashReporter(); 335 } 336 else 337 { 338 FILE *fd = fopen("logs\\service.log", "a"); 339 340 if (fd) 341 { 342 fprintf(fd, "UnrealIRCd has encountered a fatal error. Debugging information " 343 "has been dumped to unrealircd.%d.core, please file a bug and upload " 344 "this file to https://bugs.unrealircd.org/.", getpid()); 345 fclose(fd); 346 } 347 } 348 CleanUp(); 349 return EXCEPTION_EXECUTE_HANDLER; 350 } 351 352 void GotSigAbort(int signal) 353 { 354 /* I just want to call ExceptionFilter() but it requires an argument which we don't have... 355 * So just crash, which is rather silly but produces at least a crash report. 356 * Feel free to improve this! 357 */ 358 char *crash = NULL; 359 *crash = 'X'; 360 } 361 362 /* Initializes the exception handler */ 363 void InitDebug(void) 364 { 365 SetUnhandledExceptionFilter(&ExceptionFilter); 366 _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); 367 signal(SIGABRT, GotSigAbort); 368 } 369 370