LLVM API Documentation
00001 //===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file provides the Win32 specific implementation of the Signals class. 00011 // 00012 //===----------------------------------------------------------------------===// 00013 00014 #include "llvm/Support/FileSystem.h" 00015 #include <algorithm> 00016 #include <stdio.h> 00017 #include <vector> 00018 00019 // The Windows.h header must be after LLVM and standard headers. 00020 #include "WindowsSupport.h" 00021 00022 #ifdef __MINGW32__ 00023 #include <imagehlp.h> 00024 #else 00025 #include <dbghelp.h> 00026 #endif 00027 #include <psapi.h> 00028 00029 #ifdef _MSC_VER 00030 #pragma comment(lib, "psapi.lib") 00031 #pragma comment(lib, "dbghelp.lib") 00032 #elif __MINGW32__ 00033 #if ((HAVE_LIBIMAGEHLP != 1) || (HAVE_LIBPSAPI != 1)) 00034 #error "libimagehlp.a & libpsapi.a should be present" 00035 #endif 00036 // The version of g++ that comes with MinGW does *not* properly understand 00037 // the ll format specifier for printf. However, MinGW passes the format 00038 // specifiers on to the MSVCRT entirely, and the CRT understands the ll 00039 // specifier. So these warnings are spurious in this case. Since we compile 00040 // with -Wall, this will generate these warnings which should be ignored. So 00041 // we will turn off the warnings for this just file. However, MinGW also does 00042 // not support push and pop for diagnostics, so we have to manually turn it 00043 // back on at the end of the file. 00044 #pragma GCC diagnostic ignored "-Wformat" 00045 #pragma GCC diagnostic ignored "-Wformat-extra-args" 00046 00047 #if !defined(__MINGW64_VERSION_MAJOR) 00048 // MinGW.org does not have updated support for the 64-bit versions of the 00049 // DebugHlp APIs. So we will have to load them manually. The structures and 00050 // method signatures were pulled from DbgHelp.h in the Windows Platform SDK, 00051 // and adjusted for brevity. 00052 typedef struct _IMAGEHLP_LINE64 { 00053 DWORD SizeOfStruct; 00054 PVOID Key; 00055 DWORD LineNumber; 00056 PCHAR FileName; 00057 DWORD64 Address; 00058 } IMAGEHLP_LINE64, *PIMAGEHLP_LINE64; 00059 00060 typedef struct _IMAGEHLP_SYMBOL64 { 00061 DWORD SizeOfStruct; 00062 DWORD64 Address; 00063 DWORD Size; 00064 DWORD Flags; 00065 DWORD MaxNameLength; 00066 CHAR Name[1]; 00067 } IMAGEHLP_SYMBOL64, *PIMAGEHLP_SYMBOL64; 00068 00069 typedef struct _tagADDRESS64 { 00070 DWORD64 Offset; 00071 WORD Segment; 00072 ADDRESS_MODE Mode; 00073 } ADDRESS64, *LPADDRESS64; 00074 00075 typedef struct _KDHELP64 { 00076 DWORD64 Thread; 00077 DWORD ThCallbackStack; 00078 DWORD ThCallbackBStore; 00079 DWORD NextCallback; 00080 DWORD FramePointer; 00081 DWORD64 KiCallUserMode; 00082 DWORD64 KeUserCallbackDispatcher; 00083 DWORD64 SystemRangeStart; 00084 DWORD64 KiUserExceptionDispatcher; 00085 DWORD64 StackBase; 00086 DWORD64 StackLimit; 00087 DWORD64 Reserved[5]; 00088 } KDHELP64, *PKDHELP64; 00089 00090 typedef struct _tagSTACKFRAME64 { 00091 ADDRESS64 AddrPC; 00092 ADDRESS64 AddrReturn; 00093 ADDRESS64 AddrFrame; 00094 ADDRESS64 AddrStack; 00095 ADDRESS64 AddrBStore; 00096 PVOID FuncTableEntry; 00097 DWORD64 Params[4]; 00098 BOOL Far; 00099 BOOL Virtual; 00100 DWORD64 Reserved[3]; 00101 KDHELP64 KdHelp; 00102 } STACKFRAME64, *LPSTACKFRAME64; 00103 00104 typedef BOOL (__stdcall *PREAD_PROCESS_MEMORY_ROUTINE64)(HANDLE hProcess, 00105 DWORD64 qwBaseAddress, PVOID lpBuffer, DWORD nSize, 00106 LPDWORD lpNumberOfBytesRead); 00107 00108 typedef PVOID (__stdcall *PFUNCTION_TABLE_ACCESS_ROUTINE64)( HANDLE ahProcess, 00109 DWORD64 AddrBase); 00110 00111 typedef DWORD64 (__stdcall *PGET_MODULE_BASE_ROUTINE64)(HANDLE hProcess, 00112 DWORD64 Address); 00113 00114 typedef DWORD64 (__stdcall *PTRANSLATE_ADDRESS_ROUTINE64)(HANDLE hProcess, 00115 HANDLE hThread, LPADDRESS64 lpaddr); 00116 00117 typedef BOOL (WINAPI *fpStackWalk64)(DWORD, HANDLE, HANDLE, LPSTACKFRAME64, 00118 PVOID, PREAD_PROCESS_MEMORY_ROUTINE64, 00119 PFUNCTION_TABLE_ACCESS_ROUTINE64, 00120 PGET_MODULE_BASE_ROUTINE64, 00121 PTRANSLATE_ADDRESS_ROUTINE64); 00122 static fpStackWalk64 StackWalk64; 00123 00124 typedef DWORD64 (WINAPI *fpSymGetModuleBase64)(HANDLE, DWORD64); 00125 static fpSymGetModuleBase64 SymGetModuleBase64; 00126 00127 typedef BOOL (WINAPI *fpSymGetSymFromAddr64)(HANDLE, DWORD64, 00128 PDWORD64, PIMAGEHLP_SYMBOL64); 00129 static fpSymGetSymFromAddr64 SymGetSymFromAddr64; 00130 00131 typedef BOOL (WINAPI *fpSymGetLineFromAddr64)(HANDLE, DWORD64, 00132 PDWORD, PIMAGEHLP_LINE64); 00133 static fpSymGetLineFromAddr64 SymGetLineFromAddr64; 00134 00135 typedef PVOID (WINAPI *fpSymFunctionTableAccess64)(HANDLE, DWORD64); 00136 static fpSymFunctionTableAccess64 SymFunctionTableAccess64; 00137 00138 static bool load64BitDebugHelp(void) { 00139 HMODULE hLib = ::LoadLibraryW(L"Dbghelp.dll"); 00140 if (hLib) { 00141 StackWalk64 = (fpStackWalk64) 00142 ::GetProcAddress(hLib, "StackWalk64"); 00143 SymGetModuleBase64 = (fpSymGetModuleBase64) 00144 ::GetProcAddress(hLib, "SymGetModuleBase64"); 00145 SymGetSymFromAddr64 = (fpSymGetSymFromAddr64) 00146 ::GetProcAddress(hLib, "SymGetSymFromAddr64"); 00147 SymGetLineFromAddr64 = (fpSymGetLineFromAddr64) 00148 ::GetProcAddress(hLib, "SymGetLineFromAddr64"); 00149 SymFunctionTableAccess64 = (fpSymFunctionTableAccess64) 00150 ::GetProcAddress(hLib, "SymFunctionTableAccess64"); 00151 } 00152 return StackWalk64 != NULL; 00153 } 00154 #endif // !defined(__MINGW64_VERSION_MAJOR) 00155 #endif // __MINGW32__ 00156 00157 // Forward declare. 00158 static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); 00159 static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); 00160 00161 // InterruptFunction - The function to call if ctrl-c is pressed. 00162 static void (*InterruptFunction)() = 0; 00163 00164 static std::vector<std::string> *FilesToRemove = NULL; 00165 static std::vector<std::pair<void(*)(void*), void*> > *CallBacksToRun = 0; 00166 static bool RegisteredUnhandledExceptionFilter = false; 00167 static bool CleanupExecuted = false; 00168 static bool ExitOnUnhandledExceptions = false; 00169 static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; 00170 00171 // Windows creates a new thread to execute the console handler when an event 00172 // (such as CTRL/C) occurs. This causes concurrency issues with the above 00173 // globals which this critical section addresses. 00174 static CRITICAL_SECTION CriticalSection; 00175 00176 namespace llvm { 00177 00178 //===----------------------------------------------------------------------===// 00179 //=== WARNING: Implementation here must contain only Win32 specific code 00180 //=== and must not be UNIX code 00181 //===----------------------------------------------------------------------===// 00182 00183 #ifdef _MSC_VER 00184 /// AvoidMessageBoxHook - Emulates hitting "retry" from an "abort, retry, 00185 /// ignore" CRT debug report dialog. "retry" raises an exception which 00186 /// ultimately triggers our stack dumper. 00187 static int AvoidMessageBoxHook(int ReportType, char *Message, int *Return) { 00188 // Set *Return to the retry code for the return value of _CrtDbgReport: 00189 // http://msdn.microsoft.com/en-us/library/8hyw4sy7(v=vs.71).aspx 00190 // This may also trigger just-in-time debugging via DebugBreak(). 00191 if (Return) 00192 *Return = 1; 00193 // Don't call _CrtDbgReport. 00194 return TRUE; 00195 } 00196 00197 #endif 00198 00199 static void RegisterHandler() { 00200 #if __MINGW32__ && !defined(__MINGW64_VERSION_MAJOR) 00201 // On MinGW.org, we need to load up the symbols explicitly, because the 00202 // Win32 framework they include does not have support for the 64-bit 00203 // versions of the APIs we need. If we cannot load up the APIs (which 00204 // would be unexpected as they should exist on every version of Windows 00205 // we support), we will bail out since there would be nothing to report. 00206 if (!load64BitDebugHelp()) { 00207 assert(false && "These APIs should always be available"); 00208 return; 00209 } 00210 #endif 00211 00212 if (RegisteredUnhandledExceptionFilter) { 00213 EnterCriticalSection(&CriticalSection); 00214 return; 00215 } 00216 00217 // Now's the time to create the critical section. This is the first time 00218 // through here, and there's only one thread. 00219 InitializeCriticalSection(&CriticalSection); 00220 00221 // Enter it immediately. Now if someone hits CTRL/C, the console handler 00222 // can't proceed until the globals are updated. 00223 EnterCriticalSection(&CriticalSection); 00224 00225 RegisteredUnhandledExceptionFilter = true; 00226 OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); 00227 SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); 00228 00229 // Environment variable to disable any kind of crash dialog. 00230 if (getenv("LLVM_DISABLE_CRASH_REPORT")) { 00231 #ifdef _MSC_VER 00232 _CrtSetReportHook(AvoidMessageBoxHook); 00233 #endif 00234 SetErrorMode(SEM_FAILCRITICALERRORS | 00235 SEM_NOGPFAULTERRORBOX | 00236 SEM_NOOPENFILEERRORBOX); 00237 ExitOnUnhandledExceptions = true; 00238 } 00239 00240 // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or 00241 // else multi-threading problems will ensue. 00242 } 00243 00244 // RemoveFileOnSignal - The public API 00245 bool sys::RemoveFileOnSignal(StringRef Filename, std::string* ErrMsg) { 00246 RegisterHandler(); 00247 00248 if (CleanupExecuted) { 00249 if (ErrMsg) 00250 *ErrMsg = "Process terminating -- cannot register for removal"; 00251 return true; 00252 } 00253 00254 if (FilesToRemove == NULL) 00255 FilesToRemove = new std::vector<std::string>; 00256 00257 FilesToRemove->push_back(Filename); 00258 00259 LeaveCriticalSection(&CriticalSection); 00260 return false; 00261 } 00262 00263 // DontRemoveFileOnSignal - The public API 00264 void sys::DontRemoveFileOnSignal(StringRef Filename) { 00265 if (FilesToRemove == NULL) 00266 return; 00267 00268 RegisterHandler(); 00269 00270 FilesToRemove->push_back(Filename); 00271 std::vector<std::string>::reverse_iterator I = 00272 std::find(FilesToRemove->rbegin(), FilesToRemove->rend(), Filename); 00273 if (I != FilesToRemove->rend()) 00274 FilesToRemove->erase(I.base()-1); 00275 00276 LeaveCriticalSection(&CriticalSection); 00277 } 00278 00279 /// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or 00280 /// SIGSEGV) is delivered to the process, print a stack trace and then exit. 00281 void sys::PrintStackTraceOnErrorSignal() { 00282 RegisterHandler(); 00283 LeaveCriticalSection(&CriticalSection); 00284 } 00285 00286 void llvm::sys::PrintStackTrace(FILE *) { 00287 // FIXME: Implement. 00288 } 00289 00290 00291 void sys::SetInterruptFunction(void (*IF)()) { 00292 RegisterHandler(); 00293 InterruptFunction = IF; 00294 LeaveCriticalSection(&CriticalSection); 00295 } 00296 00297 00298 /// AddSignalHandler - Add a function to be called when a signal is delivered 00299 /// to the process. The handler can have a cookie passed to it to identify 00300 /// what instance of the handler it is. 00301 void sys::AddSignalHandler(void (*FnPtr)(void *), void *Cookie) { 00302 if (CallBacksToRun == 0) 00303 CallBacksToRun = new std::vector<std::pair<void(*)(void*), void*> >(); 00304 CallBacksToRun->push_back(std::make_pair(FnPtr, Cookie)); 00305 RegisterHandler(); 00306 LeaveCriticalSection(&CriticalSection); 00307 } 00308 } 00309 00310 static void Cleanup() { 00311 EnterCriticalSection(&CriticalSection); 00312 00313 // Prevent other thread from registering new files and directories for 00314 // removal, should we be executing because of the console handler callback. 00315 CleanupExecuted = true; 00316 00317 // FIXME: open files cannot be deleted. 00318 00319 if (FilesToRemove != NULL) 00320 while (!FilesToRemove->empty()) { 00321 llvm::sys::fs::remove(FilesToRemove->back()); 00322 FilesToRemove->pop_back(); 00323 } 00324 00325 if (CallBacksToRun) 00326 for (unsigned i = 0, e = CallBacksToRun->size(); i != e; ++i) 00327 (*CallBacksToRun)[i].first((*CallBacksToRun)[i].second); 00328 00329 LeaveCriticalSection(&CriticalSection); 00330 } 00331 00332 void llvm::sys::RunInterruptHandlers() { 00333 Cleanup(); 00334 } 00335 00336 static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { 00337 Cleanup(); 00338 00339 // Initialize the STACKFRAME structure. 00340 STACKFRAME64 StackFrame; 00341 memset(&StackFrame, 0, sizeof(StackFrame)); 00342 00343 DWORD machineType; 00344 #if defined(_M_X64) 00345 machineType = IMAGE_FILE_MACHINE_AMD64; 00346 StackFrame.AddrPC.Offset = ep->ContextRecord->Rip; 00347 StackFrame.AddrPC.Mode = AddrModeFlat; 00348 StackFrame.AddrStack.Offset = ep->ContextRecord->Rsp; 00349 StackFrame.AddrStack.Mode = AddrModeFlat; 00350 StackFrame.AddrFrame.Offset = ep->ContextRecord->Rbp; 00351 StackFrame.AddrFrame.Mode = AddrModeFlat; 00352 #elif defined(_M_IX86) 00353 machineType = IMAGE_FILE_MACHINE_I386; 00354 StackFrame.AddrPC.Offset = ep->ContextRecord->Eip; 00355 StackFrame.AddrPC.Mode = AddrModeFlat; 00356 StackFrame.AddrStack.Offset = ep->ContextRecord->Esp; 00357 StackFrame.AddrStack.Mode = AddrModeFlat; 00358 StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp; 00359 StackFrame.AddrFrame.Mode = AddrModeFlat; 00360 #endif 00361 00362 HANDLE hProcess = GetCurrentProcess(); 00363 HANDLE hThread = GetCurrentThread(); 00364 00365 // Initialize the symbol handler. 00366 SymSetOptions(SYMOPT_DEFERRED_LOADS|SYMOPT_LOAD_LINES); 00367 SymInitialize(hProcess, NULL, TRUE); 00368 00369 while (true) { 00370 if (!StackWalk64(machineType, hProcess, hThread, &StackFrame, 00371 ep->ContextRecord, NULL, SymFunctionTableAccess64, 00372 SymGetModuleBase64, NULL)) { 00373 break; 00374 } 00375 00376 if (StackFrame.AddrFrame.Offset == 0) 00377 break; 00378 00379 // Print the PC in hexadecimal. 00380 DWORD64 PC = StackFrame.AddrPC.Offset; 00381 #if defined(_M_X64) 00382 fprintf(stderr, "0x%016llX", PC); 00383 #elif defined(_M_IX86) 00384 fprintf(stderr, "0x%08lX", static_cast<DWORD>(PC)); 00385 #endif 00386 00387 // Print the parameters. Assume there are four. 00388 #if defined(_M_X64) 00389 fprintf(stderr, " (0x%016llX 0x%016llX 0x%016llX 0x%016llX)", 00390 StackFrame.Params[0], 00391 StackFrame.Params[1], 00392 StackFrame.Params[2], 00393 StackFrame.Params[3]); 00394 #elif defined(_M_IX86) 00395 fprintf(stderr, " (0x%08lX 0x%08lX 0x%08lX 0x%08lX)", 00396 static_cast<DWORD>(StackFrame.Params[0]), 00397 static_cast<DWORD>(StackFrame.Params[1]), 00398 static_cast<DWORD>(StackFrame.Params[2]), 00399 static_cast<DWORD>(StackFrame.Params[3])); 00400 #endif 00401 // Verify the PC belongs to a module in this process. 00402 if (!SymGetModuleBase64(hProcess, PC)) { 00403 fputs(" <unknown module>\n", stderr); 00404 continue; 00405 } 00406 00407 // Print the symbol name. 00408 char buffer[512]; 00409 IMAGEHLP_SYMBOL64 *symbol = reinterpret_cast<IMAGEHLP_SYMBOL64 *>(buffer); 00410 memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL64)); 00411 symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); 00412 symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL64); 00413 00414 DWORD64 dwDisp; 00415 if (!SymGetSymFromAddr64(hProcess, PC, &dwDisp, symbol)) { 00416 fputc('\n', stderr); 00417 continue; 00418 } 00419 00420 buffer[511] = 0; 00421 if (dwDisp > 0) 00422 fprintf(stderr, ", %s() + 0x%llX bytes(s)", symbol->Name, dwDisp); 00423 else 00424 fprintf(stderr, ", %s", symbol->Name); 00425 00426 // Print the source file and line number information. 00427 IMAGEHLP_LINE64 line; 00428 DWORD dwLineDisp; 00429 memset(&line, 0, sizeof(line)); 00430 line.SizeOfStruct = sizeof(line); 00431 if (SymGetLineFromAddr64(hProcess, PC, &dwLineDisp, &line)) { 00432 fprintf(stderr, ", %s, line %lu", line.FileName, line.LineNumber); 00433 if (dwLineDisp > 0) 00434 fprintf(stderr, " + 0x%lX byte(s)", dwLineDisp); 00435 } 00436 00437 fputc('\n', stderr); 00438 } 00439 00440 if (ExitOnUnhandledExceptions) 00441 _exit(ep->ExceptionRecord->ExceptionCode); 00442 00443 // Allow dialog box to pop up allowing choice to start debugger. 00444 if (OldFilter) 00445 return (*OldFilter)(ep); 00446 else 00447 return EXCEPTION_CONTINUE_SEARCH; 00448 } 00449 00450 static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { 00451 // We are running in our very own thread, courtesy of Windows. 00452 EnterCriticalSection(&CriticalSection); 00453 Cleanup(); 00454 00455 // If an interrupt function has been set, go and run one it; otherwise, 00456 // the process dies. 00457 void (*IF)() = InterruptFunction; 00458 InterruptFunction = 0; // Don't run it on another CTRL-C. 00459 00460 if (IF) { 00461 // Note: if the interrupt function throws an exception, there is nothing 00462 // to catch it in this thread so it will kill the process. 00463 IF(); // Run it now. 00464 LeaveCriticalSection(&CriticalSection); 00465 return TRUE; // Don't kill the process. 00466 } 00467 00468 // Allow normal processing to take place; i.e., the process dies. 00469 LeaveCriticalSection(&CriticalSection); 00470 return FALSE; 00471 } 00472 00473 #if __MINGW32__ 00474 // We turned these warnings off for this file so that MinGW-g++ doesn't 00475 // complain about the ll format specifiers used. Now we are turning the 00476 // warnings back on. If MinGW starts to support diagnostic stacks, we can 00477 // replace this with a pop. 00478 #pragma GCC diagnostic warning "-Wformat" 00479 #pragma GCC diagnostic warning "-Wformat-extra-args" 00480 #endif