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