Home | History | Annotate | Download | only in asan
      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 #include "sanitizer_common/sanitizer_libc.h"
     27 
     28 namespace __asan {
     29 
     30 // ---------------------- Stacktraces, symbols, etc. ---------------- {{{1
     31 static AsanLock dbghelp_lock(LINKER_INITIALIZED);
     32 static bool dbghelp_initialized = false;
     33 #pragma comment(lib, "dbghelp.lib")
     34 
     35 void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp) {
     36   stack->max_size = max_s;
     37   void *tmp[kStackTraceMax];
     38 
     39   // FIXME: CaptureStackBackTrace might be too slow for us.
     40   // FIXME: Compare with StackWalk64.
     41   // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
     42   uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0);
     43   uptr offset = 0;
     44   // Skip the RTL frames by searching for the PC in the stacktrace.
     45   // FIXME: this doesn't work well for the malloc/free stacks yet.
     46   for (uptr i = 0; i < cs_ret; i++) {
     47     if (pc != (uptr)tmp[i])
     48       continue;
     49     offset = i;
     50     break;
     51   }
     52 
     53   stack->size = cs_ret - offset;
     54   for (uptr i = 0; i < stack->size; i++)
     55     stack->trace[i] = (uptr)tmp[i + offset];
     56 }
     57 
     58 bool WinSymbolize(const void *addr, char *out_buffer, int buffer_size) {
     59   ScopedLock lock(&dbghelp_lock);
     60   if (!dbghelp_initialized) {
     61     SymSetOptions(SYMOPT_DEFERRED_LOADS |
     62                   SYMOPT_UNDNAME |
     63                   SYMOPT_LOAD_LINES);
     64     CHECK(SymInitialize(GetCurrentProcess(), 0, TRUE));
     65     // FIXME: We don't call SymCleanup() on exit yet - should we?
     66     dbghelp_initialized = true;
     67   }
     68 
     69   // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
     70   char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
     71   PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
     72   symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
     73   symbol->MaxNameLen = MAX_SYM_NAME;
     74   DWORD64 offset = 0;
     75   BOOL got_objname = SymFromAddr(GetCurrentProcess(),
     76                                  (DWORD64)addr, &offset, symbol);
     77   if (!got_objname)
     78     return false;
     79 
     80   DWORD  unused;
     81   IMAGEHLP_LINE64 info;
     82   info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
     83   BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(),
     84                                            (DWORD64)addr, &unused, &info);
     85   int written = 0;
     86   out_buffer[0] = '\0';
     87   // FIXME: it might be useful to print out 'obj' or 'obj+offset' info too.
     88   if (got_fileline) {
     89     written += internal_snprintf(out_buffer + written, buffer_size - written,
     90                         " %s %s:%d", symbol->Name,
     91                         info.FileName, info.LineNumber);
     92   } else {
     93     written += internal_snprintf(out_buffer + written, buffer_size - written,
     94                         " %s+0x%p", symbol->Name, offset);
     95   }
     96   return true;
     97 }
     98 
     99 // ---------------------- AsanLock ---------------- {{{1
    100 enum LockState {
    101   LOCK_UNINITIALIZED = 0,
    102   LOCK_READY = -1,
    103 };
    104 
    105 AsanLock::AsanLock(LinkerInitialized li) {
    106   // FIXME: see comments in AsanLock::Lock() for the details.
    107   CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);
    108 
    109   CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
    110   InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
    111   owner_ = LOCK_READY;
    112 }
    113 
    114 void AsanLock::Lock() {
    115   if (owner_ == LOCK_UNINITIALIZED) {
    116     // FIXME: hm, global AsanLock objects are not initialized?!?
    117     // This might be a side effect of the clang+cl+link Frankenbuild...
    118     new(this) AsanLock((LinkerInitialized)(LINKER_INITIALIZED + 1));
    119 
    120     // FIXME: If it turns out the linker doesn't invoke our
    121     // constructors, we should probably manually Lock/Unlock all the global
    122     // locks while we're starting in one thread to avoid double-init races.
    123   }
    124   EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
    125   CHECK(owner_ == LOCK_READY);
    126   owner_ = GetThreadSelf();
    127 }
    128 
    129 void AsanLock::Unlock() {
    130   CHECK(owner_ == GetThreadSelf());
    131   owner_ = LOCK_READY;
    132   LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
    133 }
    134 
    135 // ---------------------- TSD ---------------- {{{1
    136 static bool tsd_key_inited = false;
    137 
    138 static __declspec(thread) void *fake_tsd = 0;
    139 
    140 void AsanTSDInit(void (*destructor)(void *tsd)) {
    141   // FIXME: we're ignoring the destructor for now.
    142   tsd_key_inited = true;
    143 }
    144 
    145 void *AsanTSDGet() {
    146   CHECK(tsd_key_inited);
    147   return fake_tsd;
    148 }
    149 
    150 void AsanTSDSet(void *tsd) {
    151   CHECK(tsd_key_inited);
    152   fake_tsd = tsd;
    153 }
    154 
    155 // ---------------------- Various stuff ---------------- {{{1
    156 void MaybeReexec() {
    157   // No need to re-exec on Windows.
    158 }
    159 
    160 void *AsanDoesNotSupportStaticLinkage() {
    161 #if defined(_DEBUG)
    162 #error Please build the runtime with a non-debug CRT: /MD or /MT
    163 #endif
    164   return 0;
    165 }
    166 
    167 void SetAlternateSignalStack() {
    168   // FIXME: Decide what to do on Windows.
    169 }
    170 
    171 void UnsetAlternateSignalStack() {
    172   // FIXME: Decide what to do on Windows.
    173 }
    174 
    175 void InstallSignalHandlers() {
    176   // FIXME: Decide what to do on Windows.
    177 }
    178 
    179 void AsanPlatformThreadInit() {
    180   // Nothing here for now.
    181 }
    182 
    183 }  // namespace __asan
    184 
    185 #endif  // _WIN32
    186