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