asan_win.cc revision f607fc1c67a613a59a1db3c80c5d1322e1978102
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 27// Should not add dependency on libstdc++, 28// since most of the stuff here is inlinable. 29#include <algorithm> 30 31namespace __asan { 32 33// ---------------------- Stacktraces, symbols, etc. ---------------- {{{1 34static AsanLock dbghelp_lock(LINKER_INITIALIZED); 35static bool dbghelp_initialized = false; 36#pragma comment(lib, "dbghelp.lib") 37 38void AsanStackTrace::GetStackTrace(uptr max_s, uptr pc, uptr bp) { 39 max_size = max_s; 40 void *tmp[kStackTraceMax]; 41 42 // FIXME: CaptureStackBackTrace might be too slow for us. 43 // FIXME: Compare with StackWalk64. 44 // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc 45 uptr cs_ret = CaptureStackBackTrace(1, max_size, tmp, 0), 46 offset = 0; 47 // Skip the RTL frames by searching for the PC in the stacktrace. 48 // FIXME: this doesn't work well for the malloc/free stacks yet. 49 for (uptr i = 0; i < cs_ret; i++) { 50 if (pc != (uptr)tmp[i]) 51 continue; 52 offset = i; 53 break; 54 } 55 56 size = cs_ret - offset; 57 for (uptr i = 0; i < size; i++) 58 trace[i] = (uptr)tmp[i + offset]; 59} 60 61bool __asan_WinSymbolize(const void *addr, char *out_buffer, int buffer_size) { 62 ScopedLock lock(&dbghelp_lock); 63 if (!dbghelp_initialized) { 64 SymSetOptions(SYMOPT_DEFERRED_LOADS | 65 SYMOPT_UNDNAME | 66 SYMOPT_LOAD_LINES); 67 CHECK(SymInitialize(GetCurrentProcess(), 0, TRUE)); 68 // FIXME: We don't call SymCleanup() on exit yet - should we? 69 dbghelp_initialized = true; 70 } 71 72 // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx 73 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)]; 74 PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; 75 symbol->SizeOfStruct = sizeof(SYMBOL_INFO); 76 symbol->MaxNameLen = MAX_SYM_NAME; 77 DWORD64 offset = 0; 78 BOOL got_objname = SymFromAddr(GetCurrentProcess(), 79 (DWORD64)addr, &offset, symbol); 80 if (!got_objname) 81 return false; 82 83 DWORD unused; 84 IMAGEHLP_LINE64 info; 85 info.SizeOfStruct = sizeof(IMAGEHLP_LINE64); 86 BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), 87 (DWORD64)addr, &unused, &info); 88 int written = 0; 89 out_buffer[0] = '\0'; 90 // FIXME: it might be useful to print out 'obj' or 'obj+offset' info too. 91 if (got_fileline) { 92 written += SNPrintf(out_buffer + written, buffer_size - written, 93 " %s %s:%d", symbol->Name, 94 info.FileName, info.LineNumber); 95 } else { 96 written += SNPrintf(out_buffer + written, buffer_size - written, 97 " %s+0x%p", symbol->Name, offset); 98 } 99 return true; 100} 101 102// ---------------------- AsanLock ---------------- {{{1 103enum LockState { 104 LOCK_UNINITIALIZED = 0, 105 LOCK_READY = -1, 106}; 107 108AsanLock::AsanLock(LinkerInitialized li) { 109 // FIXME: see comments in AsanLock::Lock() for the details. 110 CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED); 111 112 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); 113 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 114 owner_ = LOCK_READY; 115} 116 117void AsanLock::Lock() { 118 if (owner_ == LOCK_UNINITIALIZED) { 119 // FIXME: hm, global AsanLock objects are not initialized?!? 120 // This might be a side effect of the clang+cl+link Frankenbuild... 121 new(this) AsanLock((LinkerInitialized)(LINKER_INITIALIZED + 1)); 122 123 // FIXME: If it turns out the linker doesn't invoke our 124 // constructors, we should probably manually Lock/Unlock all the global 125 // locks while we're starting in one thread to avoid double-init races. 126 } 127 EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 128 CHECK(owner_ == LOCK_READY); 129 owner_ = GetThreadSelf(); 130} 131 132void AsanLock::Unlock() { 133 CHECK(owner_ == GetThreadSelf()); 134 owner_ = LOCK_READY; 135 LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 136} 137 138// ---------------------- TSD ---------------- {{{1 139static bool tsd_key_inited = false; 140 141static __declspec(thread) void *fake_tsd = 0; 142 143void AsanTSDInit(void (*destructor)(void *tsd)) { 144 // FIXME: we're ignoring the destructor for now. 145 tsd_key_inited = true; 146} 147 148void *AsanTSDGet() { 149 CHECK(tsd_key_inited); 150 return fake_tsd; 151} 152 153void AsanTSDSet(void *tsd) { 154 CHECK(tsd_key_inited); 155 fake_tsd = tsd; 156} 157 158// ---------------------- Various stuff ---------------- {{{1 159void *AsanDoesNotSupportStaticLinkage() { 160#if defined(_DEBUG) 161#error Please build the runtime with a non-debug CRT: /MD or /MT 162#endif 163 return 0; 164} 165 166bool AsanShadowRangeIsAvailable() { 167 // FIXME: shall we do anything here on Windows? 168 return true; 169} 170 171int AtomicInc(int *a) { 172 return InterlockedExchangeAdd((LONG*)a, 1) + 1; 173} 174 175u16 AtomicExchange(u16 *a, u16 new_val) { 176 // InterlockedExchange16 seems unavailable on some MSVS installations. 177 // Everybody stand back, I pretend to know inline assembly! 178 // FIXME: I assume VC is smart enough to save/restore eax/ecx? 179 __asm { 180 mov eax, a 181 mov cx, new_val 182 xchg [eax], cx ; NOLINT 183 mov new_val, cx 184 } 185 return new_val; 186} 187 188u8 AtomicExchange(u8 *a, u8 new_val) { 189 // FIXME: can we do this with a proper xchg intrinsic? 190 u8 t = *a; 191 *a = new_val; 192 return t; 193} 194 195void AsanDumpProcessMap() { 196 UNIMPLEMENTED(); 197} 198 199uptr GetThreadSelf() { 200 return GetCurrentThreadId(); 201} 202 203void SetAlternateSignalStack() { 204 // FIXME: Decide what to do on Windows. 205} 206 207void UnsetAlternateSignalStack() { 208 // FIXME: Decide what to do on Windows. 209} 210 211void InstallSignalHandlers() { 212 // FIXME: Decide what to do on Windows. 213} 214 215void AsanDisableCoreDumper() { 216 UNIMPLEMENTED(); 217} 218 219void SleepForSeconds(int seconds) { 220 Sleep(seconds * 1000); 221} 222 223void Exit(int exitcode) { 224 _exit(exitcode); 225} 226 227void Abort() { 228 abort(); 229 _exit(-1); // abort is not NORETURN on Windows. 230} 231 232int Atexit(void (*function)(void)) { 233 return atexit(function); 234} 235 236void SortArray(uptr *array, uptr size) { 237 std::sort(array, array + size); 238} 239 240} // namespace __asan 241 242#endif // _WIN32 243