LLVM API Documentation
00001 //===- Win32/Signals.cpp - Win32 Signals Implementation ---------*- C++ -*-===// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file was developed by Jeff Cohen and is distributed under the 00006 // University of Illinois Open Source 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 "Win32.h" 00015 #include <stdio.h> 00016 #include <vector> 00017 00018 #ifdef __MINGW32__ 00019 #include <imagehlp.h> 00020 #else 00021 #include <dbghelp.h> 00022 #endif 00023 #include <psapi.h> 00024 00025 #ifdef __MINGW32__ 00026 #if ((HAVE_LIBIMAGEHLP != 1) || (HAVE_LIBPSAPI != 1)) 00027 #error "libimagehlp.a & libpsapi.a should be present" 00028 #endif 00029 #else 00030 #pragma comment(lib, "psapi.lib") 00031 #pragma comment(lib, "dbghelp.lib") 00032 #endif 00033 00034 // Forward declare. 00035 static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep); 00036 static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType); 00037 00038 // InterruptFunction - The function to call if ctrl-c is pressed. 00039 static void (*InterruptFunction)() = 0; 00040 00041 static std::vector<llvm::sys::Path> *FilesToRemove = NULL; 00042 static std::vector<llvm::sys::Path> *DirectoriesToRemove = NULL; 00043 static bool RegisteredUnhandledExceptionFilter = false; 00044 static bool CleanupExecuted = false; 00045 static PTOP_LEVEL_EXCEPTION_FILTER OldFilter = NULL; 00046 00047 // Windows creates a new thread to execute the console handler when an event 00048 // (such as CTRL/C) occurs. This causes concurrency issues with the above 00049 // globals which this critical section addresses. 00050 static CRITICAL_SECTION CriticalSection; 00051 00052 namespace llvm { 00053 00054 //===----------------------------------------------------------------------===// 00055 //=== WARNING: Implementation here must contain only Win32 specific code 00056 //=== and must not be UNIX code 00057 //===----------------------------------------------------------------------===// 00058 00059 00060 static void RegisterHandler() { 00061 if (RegisteredUnhandledExceptionFilter) { 00062 EnterCriticalSection(&CriticalSection); 00063 return; 00064 } 00065 00066 // Now's the time to create the critical section. This is the first time 00067 // through here, and there's only one thread. 00068 InitializeCriticalSection(&CriticalSection); 00069 00070 // Enter it immediately. Now if someone hits CTRL/C, the console handler 00071 // can't proceed until the globals are updated. 00072 EnterCriticalSection(&CriticalSection); 00073 00074 RegisteredUnhandledExceptionFilter = true; 00075 OldFilter = SetUnhandledExceptionFilter(LLVMUnhandledExceptionFilter); 00076 SetConsoleCtrlHandler(LLVMConsoleCtrlHandler, TRUE); 00077 00078 // IMPORTANT NOTE: Caller must call LeaveCriticalSection(&CriticalSection) or 00079 // else multi-threading problems will ensue. 00080 } 00081 00082 // RemoveFileOnSignal - The public API 00083 void sys::RemoveFileOnSignal(const sys::Path &Filename) { 00084 RegisterHandler(); 00085 00086 if (CleanupExecuted) 00087 throw std::string("Process terminating -- cannot register for removal"); 00088 00089 if (FilesToRemove == NULL) 00090 FilesToRemove = new std::vector<sys::Path>; 00091 00092 FilesToRemove->push_back(Filename); 00093 00094 LeaveCriticalSection(&CriticalSection); 00095 } 00096 00097 // RemoveDirectoryOnSignal - The public API 00098 void sys::RemoveDirectoryOnSignal(const sys::Path& path) { 00099 RegisterHandler(); 00100 00101 if (CleanupExecuted) 00102 throw std::string("Process terminating -- cannot register for removal"); 00103 00104 if (path.isDirectory()) { 00105 if (DirectoriesToRemove == NULL) 00106 DirectoriesToRemove = new std::vector<sys::Path>; 00107 00108 DirectoriesToRemove->push_back(path); 00109 } 00110 00111 LeaveCriticalSection(&CriticalSection); 00112 } 00113 00114 /// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or 00115 /// SIGSEGV) is delivered to the process, print a stack trace and then exit. 00116 void sys::PrintStackTraceOnErrorSignal() { 00117 RegisterHandler(); 00118 LeaveCriticalSection(&CriticalSection); 00119 } 00120 00121 00122 void sys::SetInterruptFunction(void (*IF)()) { 00123 RegisterHandler(); 00124 InterruptFunction = IF; 00125 LeaveCriticalSection(&CriticalSection); 00126 } 00127 } 00128 00129 static void Cleanup() { 00130 EnterCriticalSection(&CriticalSection); 00131 00132 // Prevent other thread from registering new files and directories for 00133 // removal, should we be executing because of the console handler callback. 00134 CleanupExecuted = true; 00135 00136 // FIXME: open files cannot be deleted. 00137 00138 if (FilesToRemove != NULL) 00139 while (!FilesToRemove->empty()) { 00140 try { 00141 FilesToRemove->back().eraseFromDisk(); 00142 } catch (...) { 00143 } 00144 FilesToRemove->pop_back(); 00145 } 00146 00147 if (DirectoriesToRemove != NULL) 00148 while (!DirectoriesToRemove->empty()) { 00149 try { 00150 DirectoriesToRemove->back().eraseFromDisk(true); 00151 } catch (...) { 00152 } 00153 DirectoriesToRemove->pop_back(); 00154 } 00155 00156 LeaveCriticalSection(&CriticalSection); 00157 } 00158 00159 static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { 00160 try { 00161 Cleanup(); 00162 00163 // Initialize the STACKFRAME structure. 00164 STACKFRAME StackFrame; 00165 memset(&StackFrame, 0, sizeof(StackFrame)); 00166 00167 StackFrame.AddrPC.Offset = ep->ContextRecord->Eip; 00168 StackFrame.AddrPC.Mode = AddrModeFlat; 00169 StackFrame.AddrStack.Offset = ep->ContextRecord->Esp; 00170 StackFrame.AddrStack.Mode = AddrModeFlat; 00171 StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp; 00172 StackFrame.AddrFrame.Mode = AddrModeFlat; 00173 00174 HANDLE hProcess = GetCurrentProcess(); 00175 HANDLE hThread = GetCurrentThread(); 00176 00177 // Initialize the symbol handler. 00178 SymSetOptions(SYMOPT_DEFERRED_LOADS|SYMOPT_LOAD_LINES); 00179 SymInitialize(hProcess, NULL, TRUE); 00180 00181 while (true) { 00182 if (!StackWalk(IMAGE_FILE_MACHINE_I386, hProcess, hThread, &StackFrame, 00183 ep->ContextRecord, NULL, SymFunctionTableAccess, 00184 SymGetModuleBase, NULL)) { 00185 break; 00186 } 00187 00188 if (StackFrame.AddrFrame.Offset == 0) 00189 break; 00190 00191 // Print the PC in hexadecimal. 00192 DWORD PC = StackFrame.AddrPC.Offset; 00193 fprintf(stderr, "%08X", PC); 00194 00195 // Print the parameters. Assume there are four. 00196 fprintf(stderr, " (0x%08X 0x%08X 0x%08X 0x%08X)", StackFrame.Params[0], 00197 StackFrame.Params[1], StackFrame.Params[2], StackFrame.Params[3]); 00198 00199 // Verify the PC belongs to a module in this process. 00200 if (!SymGetModuleBase(hProcess, PC)) { 00201 fputs(" <unknown module>\n", stderr); 00202 continue; 00203 } 00204 00205 // Print the symbol name. 00206 char buffer[512]; 00207 IMAGEHLP_SYMBOL *symbol = reinterpret_cast<IMAGEHLP_SYMBOL *>(buffer); 00208 memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL)); 00209 symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); 00210 symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL); 00211 00212 DWORD dwDisp; 00213 if (!SymGetSymFromAddr(hProcess, PC, &dwDisp, symbol)) { 00214 fputc('\n', stderr); 00215 continue; 00216 } 00217 00218 buffer[511] = 0; 00219 if (dwDisp > 0) 00220 fprintf(stderr, ", %s()+%04d bytes(s)", symbol->Name, dwDisp); 00221 else 00222 fprintf(stderr, ", %s", symbol->Name); 00223 00224 // Print the source file and line number information. 00225 IMAGEHLP_LINE line; 00226 memset(&line, 0, sizeof(line)); 00227 line.SizeOfStruct = sizeof(line); 00228 if (SymGetLineFromAddr(hProcess, PC, &dwDisp, &line)) { 00229 fprintf(stderr, ", %s, line %d", line.FileName, line.LineNumber); 00230 if (dwDisp > 0) 00231 fprintf(stderr, "+%04d byte(s)", dwDisp); 00232 } 00233 00234 fputc('\n', stderr); 00235 } 00236 } catch (...) { 00237 assert(!"Crashed in LLVMUnhandledExceptionFilter"); 00238 } 00239 00240 // Allow dialog box to pop up allowing choice to start debugger. 00241 if (OldFilter) 00242 return (*OldFilter)(ep); 00243 else 00244 return EXCEPTION_CONTINUE_SEARCH; 00245 } 00246 00247 static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { 00248 // We are running in our very own thread, courtesy of Windows. 00249 EnterCriticalSection(&CriticalSection); 00250 Cleanup(); 00251 00252 // If an interrupt function has been set, go and run one it; otherwise, 00253 // the process dies. 00254 void (*IF)() = InterruptFunction; 00255 InterruptFunction = 0; // Don't run it on another CTRL-C. 00256 00257 if (IF) { 00258 // Note: if the interrupt function throws an exception, there is nothing 00259 // to catch it in this thread so it will kill the process. 00260 IF(); // Run it now. 00261 LeaveCriticalSection(&CriticalSection); 00262 return TRUE; // Don't kill the process. 00263 } 00264 00265 // Allow normal processing to take place; i.e., the process dies. 00266 LeaveCriticalSection(&CriticalSection); 00267 return FALSE; 00268 } 00269