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