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