asan_win.cc revision f4f51f2cc6fa936f0c65577f82e6b62989d546ee
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 "asan_interceptors.h"
21#include "asan_internal.h"
22#include "asan_thread.h"
23#include "sanitizer_common/sanitizer_libc.h"
24#include "sanitizer_common/sanitizer_mutex.h"
25
26namespace __asan {
27
28// ---------------------- Stacktraces, symbols, etc. ---------------- {{{1
29static BlockingMutex dbghelp_lock(LINKER_INITIALIZED);
30static bool dbghelp_initialized = false;
31#pragma comment(lib, "dbghelp.lib")
32
33void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, bool fast) {
34  (void)fast;
35  stack->max_size = max_s;
36  void *tmp[kStackTraceMax];
37
38  // FIXME: CaptureStackBackTrace might be too slow for us.
39  // FIXME: Compare with StackWalk64.
40  // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
41  uptr cs_ret = CaptureStackBackTrace(1, stack->max_size, tmp, 0);
42  uptr offset = 0;
43  // Skip the RTL frames by searching for the PC in the stacktrace.
44  // FIXME: this doesn't work well for the malloc/free stacks yet.
45  for (uptr i = 0; i < cs_ret; i++) {
46    if (pc != (uptr)tmp[i])
47      continue;
48    offset = i;
49    break;
50  }
51
52  stack->size = cs_ret - offset;
53  for (uptr i = 0; i < stack->size; i++)
54    stack->trace[i] = (uptr)tmp[i + offset];
55}
56
57// ---------------------- TSD ---------------- {{{1
58static bool tsd_key_inited = false;
59
60static __declspec(thread) void *fake_tsd = 0;
61
62void AsanTSDInit(void (*destructor)(void *tsd)) {
63  // FIXME: we're ignoring the destructor for now.
64  tsd_key_inited = true;
65}
66
67void *AsanTSDGet() {
68  CHECK(tsd_key_inited);
69  return fake_tsd;
70}
71
72void AsanTSDSet(void *tsd) {
73  CHECK(tsd_key_inited);
74  fake_tsd = tsd;
75}
76
77// ---------------------- Various stuff ---------------- {{{1
78void MaybeReexec() {
79  // No need to re-exec on Windows.
80}
81
82void *AsanDoesNotSupportStaticLinkage() {
83#if defined(_DEBUG)
84#error Please build the runtime with a non-debug CRT: /MD or /MT
85#endif
86  return 0;
87}
88
89void SetAlternateSignalStack() {
90  // FIXME: Decide what to do on Windows.
91}
92
93void UnsetAlternateSignalStack() {
94  // FIXME: Decide what to do on Windows.
95}
96
97void InstallSignalHandlers() {
98  // FIXME: Decide what to do on Windows.
99}
100
101void AsanPlatformThreadInit() {
102  // Nothing here for now.
103}
104
105void ClearShadowMemoryForContext(void *context) {
106  UNIMPLEMENTED();
107}
108
109}  // namespace __asan
110
111// ---------------------- Interface ---------------- {{{1
112using namespace __asan;  // NOLINT
113
114extern "C" {
115SANITIZER_INTERFACE_ATTRIBUTE NOINLINE
116bool __asan_symbolize(const void *addr, char *out_buffer, int buffer_size) {
117  BlockingMutexLock lock(&dbghelp_lock);
118  if (!dbghelp_initialized) {
119    SymSetOptions(SYMOPT_DEFERRED_LOADS |
120                  SYMOPT_UNDNAME |
121                  SYMOPT_LOAD_LINES);
122    CHECK(SymInitialize(GetCurrentProcess(), 0, TRUE));
123    // FIXME: We don't call SymCleanup() on exit yet - should we?
124    dbghelp_initialized = true;
125  }
126
127  // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
128  char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
129  PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
130  symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
131  symbol->MaxNameLen = MAX_SYM_NAME;
132  DWORD64 offset = 0;
133  BOOL got_objname = SymFromAddr(GetCurrentProcess(),
134                                 (DWORD64)addr, &offset, symbol);
135  if (!got_objname)
136    return false;
137
138  DWORD  unused;
139  IMAGEHLP_LINE64 info;
140  info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
141  BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(),
142                                           (DWORD64)addr, &unused, &info);
143  int written = 0;
144  out_buffer[0] = '\0';
145  // FIXME: it might be useful to print out 'obj' or 'obj+offset' info too.
146  if (got_fileline) {
147    written += internal_snprintf(out_buffer + written, buffer_size - written,
148                        " %s %s:%d", symbol->Name,
149                        info.FileName, info.LineNumber);
150  } else {
151    written += internal_snprintf(out_buffer + written, buffer_size - written,
152                        " %s+0x%p", symbol->Name, offset);
153  }
154  return true;
155}
156}  // extern "C"
157
158
159#endif  // _WIN32
160