asan_win.cc revision e1fe0fd868886b53cb8d5d957afebbdd47688df7
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 <stdio.h> // FIXME: get rid of this. 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 28namespace __asan { 29 30// ---------------------- Memory management ---------------- {{{1 31void *AsanMmapFixedNoReserve(uintptr_t fixed_addr, size_t size) { 32 return VirtualAlloc((LPVOID)fixed_addr, size, 33 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 34} 35 36void *AsanMmapSomewhereOrDie(size_t size, const char *mem_type) { 37 void *rv = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 38 if (rv == NULL) 39 OutOfMemoryMessageAndDie(mem_type, size); 40 return rv; 41} 42 43void *AsanMprotect(uintptr_t fixed_addr, size_t size) { 44 return VirtualAlloc((LPVOID)fixed_addr, size, 45 MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS); 46} 47 48void AsanUnmapOrDie(void *addr, size_t size) { 49 UNIMPLEMENTED(); 50} 51 52// ---------------------- IO ---------------- {{{1 53size_t AsanWrite(int fd, const void *buf, size_t count) { 54 if (fd != 2) 55 UNIMPLEMENTED(); 56 57 // FIXME: use WriteFile instead? 58 return fwrite(buf, 1, count, stderr); 59} 60 61// FIXME: Looks like these functions are not needed and are linked in by the 62// code unreachable on Windows. We should clean this up. 63int AsanOpenReadonly(const char* filename) { 64 UNIMPLEMENTED(); 65 return -1; 66} 67 68size_t AsanRead(int fd, void *buf, size_t count) { 69 UNIMPLEMENTED(); 70 return -1; 71} 72 73int AsanClose(int fd) { 74 UNIMPLEMENTED(); 75 return -1; 76} 77 78// ---------------------- Stacktraces, symbols, etc. ---------------- {{{1 79static AsanLock dbghelp_lock(LINKER_INITIALIZED); 80static bool dbghelp_initialized = false; 81#pragma comment(lib, "dbghelp.lib") 82 83void AsanThread::SetThreadStackTopAndBottom() { 84 MEMORY_BASIC_INFORMATION mbi; 85 CHECK(VirtualQuery(&mbi /* on stack */, 86 &mbi, sizeof(mbi)) != 0); 87 // FIXME: is it possible for the stack to not be a single allocation? 88 // Are these values what ASan expects to get (reserved, not committed; 89 // including stack guard page) ? 90 stack_top_ = (uintptr_t)mbi.BaseAddress + mbi.RegionSize; 91 stack_bottom_ = (uintptr_t)mbi.AllocationBase; 92} 93 94void AsanStackTrace::GetStackTrace(size_t max_s, uintptr_t pc, uintptr_t bp) { 95 max_size = max_s; 96 void *tmp[kStackTraceMax]; 97 98 // FIXME: CaptureStackBackTrace might be too slow for us. 99 // FIXME: Compare with StackWalk64. 100 // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc 101 size_t cs_ret = CaptureStackBackTrace(1, max_size, tmp, NULL), 102 offset = 0; 103 // Skip the RTL frames by searching for the PC in the stacktrace. 104 // FIXME: this doesn't work well for the malloc/free stacks yet. 105 for (size_t i = 0; i < cs_ret; i++) { 106 if (pc != (uintptr_t)tmp[i]) 107 continue; 108 offset = i; 109 break; 110 } 111 112 size = cs_ret - offset; 113 for (size_t i = 0; i < size; i++) 114 trace[i] = (uintptr_t)tmp[i + offset]; 115} 116 117bool WinSymbolize(const void *addr, char *out_buffer, int buffer_size) { 118 ScopedLock lock(&dbghelp_lock); 119 if (!dbghelp_initialized) { 120 SymSetOptions(SYMOPT_DEFERRED_LOADS | 121 SYMOPT_UNDNAME | 122 SYMOPT_LOAD_LINES); 123 CHECK(SymInitialize(GetCurrentProcess(), NULL, TRUE)); 124 // FIXME: We don't call SymCleanup() on exit yet - should we? 125 dbghelp_initialized = true; 126 } 127 128 // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx 129 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)]; 130 PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer; 131 symbol->SizeOfStruct = sizeof(SYMBOL_INFO); 132 symbol->MaxNameLen = MAX_SYM_NAME; 133 DWORD64 offset = 0; 134 BOOL got_objname = SymFromAddr(GetCurrentProcess(), 135 (DWORD64)addr, &offset, symbol); 136 if (!got_objname) 137 return false; 138 139 DWORD unused; 140 IMAGEHLP_LINE64 info; 141 info.SizeOfStruct = sizeof(IMAGEHLP_LINE64); 142 BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(), 143 (DWORD64)addr, &unused, &info); 144 int written = 0; 145 out_buffer[0] = '\0'; 146 // FIXME: it might be useful to print out 'obj' or 'obj+offset' info too. 147 if (got_fileline) { 148 written += SNPrintf(out_buffer + written, buffer_size - written, 149 " %s %s:%d", symbol->Name, 150 info.FileName, info.LineNumber); 151 } else { 152 written += SNPrintf(out_buffer + written, buffer_size - written, 153 " %s+0x%p", symbol->Name, offset); 154 } 155 return true; 156} 157 158// ---------------------- AsanLock ---------------- {{{1 159enum LockState { 160 LOCK_UNINITIALIZED = 0, 161 LOCK_READY = -1, 162}; 163 164AsanLock::AsanLock(LinkerInitialized li) { 165 // FIXME: see comments in AsanLock::Lock() for the details. 166 CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED); 167 168 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_)); 169 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 170 owner_ = LOCK_READY; 171} 172 173void AsanLock::Lock() { 174 if (owner_ == LOCK_UNINITIALIZED) { 175 // FIXME: hm, global AsanLock objects are not initialized?!? 176 // This might be a side effect of the clang+cl+link Frankenbuild... 177 new(this) AsanLock((LinkerInitialized)(LINKER_INITIALIZED + 1)); 178 179 // FIXME: If it turns out the linker doesn't invoke our 180 // constructors, we should probably manually Lock/Unlock all the global 181 // locks while we're starting in one thread to avoid double-init races. 182 } 183 EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 184 CHECK(owner_ == LOCK_READY); 185 owner_ = GetThreadSelf(); 186} 187 188void AsanLock::Unlock() { 189 CHECK(owner_ == GetThreadSelf()); 190 owner_ = LOCK_READY; 191 LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_); 192} 193 194// ---------------------- TSD ---------------- {{{1 195static bool tsd_key_inited = false; 196 197// FIXME: is __declspec enough? 198static __declspec(thread) void *fake_tsd = NULL; 199 200void AsanTSDInit(void (*destructor)(void *tsd)) { 201 // FIXME: we're ignoring the destructor for now. 202 tsd_key_inited = true; 203} 204 205void *AsanTSDGet() { 206 CHECK(tsd_key_inited); 207 return fake_tsd; 208} 209 210void AsanTSDSet(void *tsd) { 211 CHECK(tsd_key_inited); 212 fake_tsd = tsd; 213} 214 215// ---------------------- Various stuff ---------------- {{{1 216void *AsanDoesNotSupportStaticLinkage() { 217 // FIXME: shall we do anything here on Windows? 218 return NULL; 219} 220 221bool AsanShadowRangeIsAvailable() { 222 // FIXME: shall we do anything here on Windows? 223 return true; 224} 225 226int AtomicInc(int *a) { 227 return InterlockedExchangeAdd((LONG*)a, 1) + 1; 228} 229 230const char* AsanGetEnv(const char* name) { 231 // FIXME: implement. 232 return NULL; 233} 234 235int GetPid() { 236 return GetProcessId(GetCurrentProcess()); 237} 238 239uintptr_t GetThreadSelf() { 240 return GetCurrentThreadId(); 241} 242 243void InstallSignalHandlers() { 244 // FIXME: Decide what to do on Windows. 245} 246 247void AsanDisableCoreDumper() { 248 UNIMPLEMENTED(); 249} 250 251void SleepForSeconds(int seconds) { 252 Sleep(seconds * 1000); 253} 254 255void Exit(int exitcode) { 256 _exit(exitcode); 257} 258 259} // namespace __asan 260 261#endif // _WIN32 262