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