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 "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 bool sys::RemoveFileOnSignal(const sys::Path &Filename, std::string* ErrMsg) { 00084 RegisterHandler(); 00085 00086 if (CleanupExecuted) { 00087 if (ErrMsg) 00088 *ErrMsg = "Process terminating -- cannot register for removal"; 00089 return true; 00090 } 00091 00092 if (FilesToRemove == NULL) 00093 FilesToRemove = new std::vector<sys::Path>; 00094 00095 FilesToRemove->push_back(Filename); 00096 00097 LeaveCriticalSection(&CriticalSection); 00098 return false; 00099 } 00100 00101 // RemoveDirectoryOnSignal - The public API 00102 bool sys::RemoveDirectoryOnSignal(const sys::Path& path, std::string* ErrMsg) { 00103 // Not a directory? 00104 WIN32_FILE_ATTRIBUTE_DATA fi; 00105 if (!GetFileAttributesEx(path.c_str(), GetFileExInfoStandard, &fi)) { 00106 MakeErrMsg(ErrMsg, path.toString() + ": can't get status of file"); 00107 return true; 00108 } 00109 00110 if (!(fi.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { 00111 if (ErrMsg) 00112 *ErrMsg = path.toString() + ": not a directory"; 00113 return true; 00114 } 00115 00116 RegisterHandler(); 00117 00118 if (CleanupExecuted) { 00119 if (ErrMsg) 00120 *ErrMsg = "Process terminating -- cannot register for removal"; 00121 return true; 00122 } 00123 00124 if (DirectoriesToRemove == NULL) 00125 DirectoriesToRemove = new std::vector<sys::Path>; 00126 DirectoriesToRemove->push_back(path); 00127 00128 LeaveCriticalSection(&CriticalSection); 00129 return false; 00130 } 00131 00132 /// PrintStackTraceOnErrorSignal - When an error signal (such as SIBABRT or 00133 /// SIGSEGV) is delivered to the process, print a stack trace and then exit. 00134 void sys::PrintStackTraceOnErrorSignal() { 00135 RegisterHandler(); 00136 LeaveCriticalSection(&CriticalSection); 00137 } 00138 00139 00140 void sys::SetInterruptFunction(void (*IF)()) { 00141 RegisterHandler(); 00142 InterruptFunction = IF; 00143 LeaveCriticalSection(&CriticalSection); 00144 } 00145 } 00146 00147 static void Cleanup() { 00148 EnterCriticalSection(&CriticalSection); 00149 00150 // Prevent other thread from registering new files and directories for 00151 // removal, should we be executing because of the console handler callback. 00152 CleanupExecuted = true; 00153 00154 // FIXME: open files cannot be deleted. 00155 00156 if (FilesToRemove != NULL) 00157 while (!FilesToRemove->empty()) { 00158 try { 00159 FilesToRemove->back().eraseFromDisk(); 00160 } catch (...) { 00161 } 00162 FilesToRemove->pop_back(); 00163 } 00164 00165 if (DirectoriesToRemove != NULL) 00166 while (!DirectoriesToRemove->empty()) { 00167 try { 00168 DirectoriesToRemove->back().eraseFromDisk(true); 00169 } catch (...) { 00170 } 00171 DirectoriesToRemove->pop_back(); 00172 } 00173 00174 LeaveCriticalSection(&CriticalSection); 00175 } 00176 00177 static LONG WINAPI LLVMUnhandledExceptionFilter(LPEXCEPTION_POINTERS ep) { 00178 try { 00179 Cleanup(); 00180 00181 #ifdef _WIN64 00182 // TODO: provide a x64 friendly version of the following 00183 #else 00184 00185 // Initialize the STACKFRAME structure. 00186 STACKFRAME StackFrame; 00187 memset(&StackFrame, 0, sizeof(StackFrame)); 00188 00189 StackFrame.AddrPC.Offset = ep->ContextRecord->Eip; 00190 StackFrame.AddrPC.Mode = AddrModeFlat; 00191 StackFrame.AddrStack.Offset = ep->ContextRecord->Esp; 00192 StackFrame.AddrStack.Mode = AddrModeFlat; 00193 StackFrame.AddrFrame.Offset = ep->ContextRecord->Ebp; 00194 StackFrame.AddrFrame.Mode = AddrModeFlat; 00195 00196 HANDLE hProcess = GetCurrentProcess(); 00197 HANDLE hThread = GetCurrentThread(); 00198 00199 // Initialize the symbol handler. 00200 SymSetOptions(SYMOPT_DEFERRED_LOADS|SYMOPT_LOAD_LINES); 00201 SymInitialize(hProcess, NULL, TRUE); 00202 00203 while (true) { 00204 if (!StackWalk(IMAGE_FILE_MACHINE_I386, hProcess, hThread, &StackFrame, 00205 ep->ContextRecord, NULL, SymFunctionTableAccess, 00206 SymGetModuleBase, NULL)) { 00207 break; 00208 } 00209 00210 if (StackFrame.AddrFrame.Offset == 0) 00211 break; 00212 00213 // Print the PC in hexadecimal. 00214 DWORD PC = StackFrame.AddrPC.Offset; 00215 fprintf(stderr, "%08X", PC); 00216 00217 // Print the parameters. Assume there are four. 00218 fprintf(stderr, " (0x%08X 0x%08X 0x%08X 0x%08X)", StackFrame.Params[0], 00219 StackFrame.Params[1], StackFrame.Params[2], StackFrame.Params[3]); 00220 00221 // Verify the PC belongs to a module in this process. 00222 if (!SymGetModuleBase(hProcess, PC)) { 00223 fputs(" <unknown module>\n", stderr); 00224 continue; 00225 } 00226 00227 // Print the symbol name. 00228 char buffer[512]; 00229 IMAGEHLP_SYMBOL *symbol = reinterpret_cast<IMAGEHLP_SYMBOL *>(buffer); 00230 memset(symbol, 0, sizeof(IMAGEHLP_SYMBOL)); 00231 symbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL); 00232 symbol->MaxNameLength = 512 - sizeof(IMAGEHLP_SYMBOL); 00233 00234 DWORD dwDisp; 00235 if (!SymGetSymFromAddr(hProcess, PC, &dwDisp, symbol)) { 00236 fputc('\n', stderr); 00237 continue; 00238 } 00239 00240 buffer[511] = 0; 00241 if (dwDisp > 0) 00242 fprintf(stderr, ", %s()+%04d bytes(s)", symbol->Name, dwDisp); 00243 else 00244 fprintf(stderr, ", %s", symbol->Name); 00245 00246 // Print the source file and line number information. 00247 IMAGEHLP_LINE line; 00248 memset(&line, 0, sizeof(line)); 00249 line.SizeOfStruct = sizeof(line); 00250 if (SymGetLineFromAddr(hProcess, PC, &dwDisp, &line)) { 00251 fprintf(stderr, ", %s, line %d", line.FileName, line.LineNumber); 00252 if (dwDisp > 0) 00253 fprintf(stderr, "+%04d byte(s)", dwDisp); 00254 } 00255 00256 fputc('\n', stderr); 00257 } 00258 00259 #endif 00260 00261 } catch (...) { 00262 assert(!"Crashed in LLVMUnhandledExceptionFilter"); 00263 } 00264 00265 // Allow dialog box to pop up allowing choice to start debugger. 00266 if (OldFilter) 00267 return (*OldFilter)(ep); 00268 else 00269 return EXCEPTION_CONTINUE_SEARCH; 00270 } 00271 00272 static BOOL WINAPI LLVMConsoleCtrlHandler(DWORD dwCtrlType) { 00273 // We are running in our very own thread, courtesy of Windows. 00274 EnterCriticalSection(&CriticalSection); 00275 Cleanup(); 00276 00277 // If an interrupt function has been set, go and run one it; otherwise, 00278 // the process dies. 00279 void (*IF)() = InterruptFunction; 00280 InterruptFunction = 0; // Don't run it on another CTRL-C. 00281 00282 if (IF) { 00283 // Note: if the interrupt function throws an exception, there is nothing 00284 // to catch it in this thread so it will kill the process. 00285 IF(); // Run it now. 00286 LeaveCriticalSection(&CriticalSection); 00287 return TRUE; // Don't kill the process. 00288 } 00289 00290 // Allow normal processing to take place; i.e., the process dies. 00291 LeaveCriticalSection(&CriticalSection); 00292 return FALSE; 00293 } 00294
This web site is hosted by the Computer Science Department at the University of Illinois at Urbana-Champaign.