1 //===-- asan_win.cc -------------------------------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // This file is a part of AddressSanitizer, an address sanity checker. 11 // 12 // Windows-specific details. 13 //===----------------------------------------------------------------------===// 14 #ifdef _WIN32 15 #include <windows.h> 16 17 #include <dbghelp.h> 18 #include <stdlib.h> 19 20 #include <new> // FIXME: temporarily needed for placement new in AsanLock. 21 22 #include "asan_interceptors.h" 23 #include "asan_internal.h" 24 #include "asan_lock.h" 25 #include "asan_thread.h" 26 #include "sanitizer_common/sanitizer_libc.h" 27 28 namespace __asan { 29 30 // ---------------------- Stacktraces, symbols, etc. ---------------- {{{1 31 static AsanLock dbghelp_lock(LINKER_INITIALIZED); 32 static bool dbghelp_initialized = false; 33 #pragma comment(lib, "dbghelp.lib") 34 35 void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp) { 36 stack->max_size = max_s; 37 void *tmp[kStackTraceMax]; 38 39 // FIXME: CaptureStackBackTrace might be too slow for us. 40 // FIXME: Compare with StackWalk64. 41 // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc 42 uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0); 43 uptr offset = 0; 44 // Skip the RTL frames by searching for the PC in the stacktrace. 45 // FIXME: this doesn't work well for the malloc/free stacks yet. 46 for (uptr i = 0; i < cs_ret; i++) { 47 if (pc != (uptr)tmp[i]) 48 continue; 49 offset = i; 50 break; 51 } 52 53 stack->size = cs_ret - offset; 54 for (uptr i = 0; i < stack->size; i++) 55 stack->trace[i] = (uptr)tmp[i + offset]; 56 } 57 58 bool WinSymbolize(const void *addr, char *out_buffer, int buffer_size) { 59 ScopedLock lock(&dbghelp_lock); 60 if (!dbghelp_initialized) { 61 SymSetOptions(SYMOPT_DEFERRED_LOADS | 62 SYMOPT_UNDNAME | 63 SYMOPT_LOAD_LINES); 64 CHECK(SymInitialize(GetCurrentProcess(), 0, TRUE)); 65 // FIXME: We don't call SymCleanup() on exit yet - should we? 66 dbghelp_initialized = true; 67 } 68 69 // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx 70 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)]; 71 PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; 72 symbol->SizeOfStruct = sizeof(SYMBOL_INFO); 73 symbol->MaxNameLen = MAX_SYM_NAME; 74 DWORD64 offset = 0; 75 BOOL got_objname = SymFromAddr(GetCurrentProcess(), 76 (DWORD64)addr, &offset, symbol); 77 if (!got_objname) 78 return false; 79 80 DWORD unused; 81 IMAGEHLP_LINE64 info; 82 info.SizeOfStruct = sizeof(IMAGEHLP_LINE64); 83 BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), 84 (DWORD64)addr, &unused, &info); 85 int written = 0; 86 out_buffer[0] = '\0'; 87 // FIXME: it might be useful to print out 'obj' or 'obj+offset' info too. 88 if (got_fileline) { 89 written += internal_snprintf(out_buffer + written, buffer_size - written, 90 " %s %s:%d", symbol->Name, 91 info.FileName, info.LineNumber); 92 } else { 93 written += internal_snprintf(out_buffer + written, buffer_size - written, 94 " %s+0x%p", symbol->Name, offset); 95 } 96 return true; 97 } 98 99 // ---------------------- AsanLock ---------------- {{{1 100 enum LockState { 101 LOCK_UNINITIALIZED = 0, 102 LOCK_READY = -1, 103 }; 104 105 AsanLock::AsanLock(LinkerInitialized li) { 106 // FIXME: see comments in AsanLock::Lock() for the details. 107 CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED); 108 109 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); 110 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 111 owner_ = LOCK_READY; 112 } 113 114 void AsanLock::Lock() { 115 if (owner_ == LOCK_UNINITIALIZED) { 116 // FIXME: hm, global AsanLock objects are not initialized?!? 117 // This might be a side effect of the clang+cl+link Frankenbuild... 118 new(this) AsanLock((LinkerInitialized)(LINKER_INITIALIZED + 1)); 119 120 // FIXME: If it turns out the linker doesn't invoke our 121 // constructors, we should probably manually Lock/Unlock all the global 122 // locks while we're starting in one thread to avoid double-init races. 123 } 124 EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 125 CHECK(owner_ == LOCK_READY); 126 owner_ = GetThreadSelf(); 127 } 128 129 void AsanLock::Unlock() { 130 CHECK(owner_ == GetThreadSelf()); 131 owner_ = LOCK_READY; 132 LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 133 } 134 135 // ---------------------- TSD ---------------- {{{1 136 static bool tsd_key_inited = false; 137 138 static __declspec(thread) void *fake_tsd = 0; 139 140 void AsanTSDInit(void (*destructor)(void *tsd)) { 141 // FIXME: we're ignoring the destructor for now. 142 tsd_key_inited = true; 143 } 144 145 void *AsanTSDGet() { 146 CHECK(tsd_key_inited); 147 return fake_tsd; 148 } 149 150 void AsanTSDSet(void *tsd) { 151 CHECK(tsd_key_inited); 152 fake_tsd = tsd; 153 } 154 155 // ---------------------- Various stuff ---------------- {{{1 156 void MaybeReexec() { 157 // No need to re-exec on Windows. 158 } 159 160 void *AsanDoesNotSupportStaticLinkage() { 161 #if defined(_DEBUG) 162 #error Please build the runtime with a non-debug CRT: /MD or /MT 163 #endif 164 return 0; 165 } 166 167 void SetAlternateSignalStack() { 168 // FIXME: Decide what to do on Windows. 169 } 170 171 void UnsetAlternateSignalStack() { 172 // FIXME: Decide what to do on Windows. 173 } 174 175 void InstallSignalHandlers() { 176 // FIXME: Decide what to do on Windows. 177 } 178 179 void AsanPlatformThreadInit() { 180 // Nothing here for now. 181 } 182 183 } // namespace __asan 184 185 #endif // _WIN32 186