blob: d47ff08e9e0c016cdb63013ac5ae56000593c479 [file] [log] [blame]
Timur Iskhodzhanov3e81fe42012-02-09 17:20:14 +00001//===-- 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.
Alexey Samsonovb823e3c2012-02-22 14:07:06 +000019#include <stdlib.h>
Timur Iskhodzhanov3e81fe42012-02-09 17:20:14 +000020
21#include <new> // FIXME: temporarily needed for placement new in AsanLock.
22
23#include "asan_interceptors.h"
24#include "asan_internal.h"
25#include "asan_lock.h"
26#include "asan_procmaps.h"
27#include "asan_thread.h"
28
29namespace __asan {
30
31// ---------------------- Memory management ---------------- {{{1
32void *AsanMmapFixedNoReserve(uintptr_t fixed_addr, size_t size) {
33 return VirtualAlloc((LPVOID)fixed_addr, size,
34 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
35}
36
37void *AsanMmapSomewhereOrDie(size_t size, const char *mem_type) {
38 void *rv = VirtualAlloc(NULL, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
39 if (rv == NULL)
40 OutOfMemoryMessageAndDie(mem_type, size);
41 return rv;
42}
43
44void *AsanMprotect(uintptr_t fixed_addr, size_t size) {
45 return VirtualAlloc((LPVOID)fixed_addr, size,
46 MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
47}
48
49void AsanUnmapOrDie(void *addr, size_t size) {
Timur Iskhodzhanov600972e2012-02-24 15:28:43 +000050 CHECK(VirtualFree(addr, size, MEM_DECOMMIT));
Timur Iskhodzhanov3e81fe42012-02-09 17:20:14 +000051}
Timur Iskhodzhanov3e81fe42012-02-09 17:20:14 +000052
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}
Timur Iskhodzhanov3e81fe42012-02-09 17:20:14 +000078
79// ---------------------- Stacktraces, symbols, etc. ---------------- {{{1
80static AsanLock dbghelp_lock(LINKER_INITIALIZED);
81static bool dbghelp_initialized = false;
82#pragma comment(lib, "dbghelp.lib")
83
84void AsanThread::SetThreadStackTopAndBottom() {
85 MEMORY_BASIC_INFORMATION mbi;
86 CHECK(VirtualQuery(&mbi /* on stack */,
87 &mbi, sizeof(mbi)) != 0);
88 // FIXME: is it possible for the stack to not be a single allocation?
89 // Are these values what ASan expects to get (reserved, not committed;
90 // including stack guard page) ?
91 stack_top_ = (uintptr_t)mbi.BaseAddress + mbi.RegionSize;
92 stack_bottom_ = (uintptr_t)mbi.AllocationBase;
93}
94
95void AsanStackTrace::GetStackTrace(size_t max_s, uintptr_t pc, uintptr_t bp) {
96 max_size = max_s;
97 void *tmp[kStackTraceMax];
98
99 // FIXME: CaptureStackBackTrace might be too slow for us.
100 // FIXME: Compare with StackWalk64.
101 // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
102 size_t cs_ret = CaptureStackBackTrace(1, max_size, tmp, NULL),
103 offset = 0;
104 // Skip the RTL frames by searching for the PC in the stacktrace.
105 // FIXME: this doesn't work well for the malloc/free stacks yet.
106 for (size_t i = 0; i < cs_ret; i++) {
107 if (pc != (uintptr_t)tmp[i])
108 continue;
109 offset = i;
110 break;
111 }
112
113 size = cs_ret - offset;
114 for (size_t i = 0; i < size; i++)
115 trace[i] = (uintptr_t)tmp[i + offset];
116}
117
118bool WinSymbolize(const void *addr, char *out_buffer, int buffer_size) {
119 ScopedLock lock(&dbghelp_lock);
120 if (!dbghelp_initialized) {
121 SymSetOptions(SYMOPT_DEFERRED_LOADS |
122 SYMOPT_UNDNAME |
123 SYMOPT_LOAD_LINES);
124 CHECK(SymInitialize(GetCurrentProcess(), NULL, TRUE));
125 // FIXME: We don't call SymCleanup() on exit yet - should we?
126 dbghelp_initialized = true;
127 }
128
129 // See http://msdn.microsoft.com/en-us/library/ms680578(VS.85).aspx
130 char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(CHAR)];
131 PSYMBOL_INFO symbol = (PSYMBOL_INFO)buffer;
132 symbol->SizeOfStruct = sizeof(SYMBOL_INFO);
133 symbol->MaxNameLen = MAX_SYM_NAME;
134 DWORD64 offset = 0;
135 BOOL got_objname = SymFromAddr(GetCurrentProcess(),
136 (DWORD64)addr, &offset, symbol);
137 if (!got_objname)
138 return false;
139
140 DWORD unused;
141 IMAGEHLP_LINE64 info;
142 info.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
143 BOOL got_fileline = SymGetLineFromAddr64(GetCurrentProcess(),
144 (DWORD64)addr, &unused, &info);
145 int written = 0;
146 out_buffer[0] = '\0';
147 // FIXME: it might be useful to print out 'obj' or 'obj+offset' info too.
148 if (got_fileline) {
149 written += SNPrintf(out_buffer + written, buffer_size - written,
150 " %s %s:%d", symbol->Name,
151 info.FileName, info.LineNumber);
152 } else {
153 written += SNPrintf(out_buffer + written, buffer_size - written,
154 " %s+0x%p", symbol->Name, offset);
155 }
156 return true;
157}
Timur Iskhodzhanov3e81fe42012-02-09 17:20:14 +0000158
159// ---------------------- AsanLock ---------------- {{{1
160enum LockState {
161 LOCK_UNINITIALIZED = 0,
162 LOCK_READY = -1,
163};
164
165AsanLock::AsanLock(LinkerInitialized li) {
166 // FIXME: see comments in AsanLock::Lock() for the details.
167 CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);
168
169 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
170 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
171 owner_ = LOCK_READY;
172}
173
174void AsanLock::Lock() {
175 if (owner_ == LOCK_UNINITIALIZED) {
176 // FIXME: hm, global AsanLock objects are not initialized?!?
177 // This might be a side effect of the clang+cl+link Frankenbuild...
178 new(this) AsanLock((LinkerInitialized)(LINKER_INITIALIZED + 1));
179
180 // FIXME: If it turns out the linker doesn't invoke our
181 // constructors, we should probably manually Lock/Unlock all the global
182 // locks while we're starting in one thread to avoid double-init races.
183 }
184 EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
185 CHECK(owner_ == LOCK_READY);
186 owner_ = GetThreadSelf();
187}
188
189void AsanLock::Unlock() {
190 CHECK(owner_ == GetThreadSelf());
191 owner_ = LOCK_READY;
192 LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
193}
Timur Iskhodzhanov3e81fe42012-02-09 17:20:14 +0000194
195// ---------------------- TSD ---------------- {{{1
196static bool tsd_key_inited = false;
197
198// FIXME: is __declspec enough?
199static __declspec(thread) void *fake_tsd = NULL;
200
201void AsanTSDInit(void (*destructor)(void *tsd)) {
202 // FIXME: we're ignoring the destructor for now.
203 tsd_key_inited = true;
204}
205
206void *AsanTSDGet() {
207 CHECK(tsd_key_inited);
208 return fake_tsd;
209}
210
211void AsanTSDSet(void *tsd) {
212 CHECK(tsd_key_inited);
213 fake_tsd = tsd;
214}
Timur Iskhodzhanov3e81fe42012-02-09 17:20:14 +0000215
216// ---------------------- Various stuff ---------------- {{{1
217void *AsanDoesNotSupportStaticLinkage() {
Timur Iskhodzhanov07bb9f12012-02-22 13:59:49 +0000218#if !defined(_DLL) || defined(_DEBUG)
219#error Please build the runtime with /MD
220#endif
Timur Iskhodzhanov3e81fe42012-02-09 17:20:14 +0000221 return NULL;
222}
223
Alexander Potapenkof73a6a32012-02-13 17:09:40 +0000224bool AsanShadowRangeIsAvailable() {
225 // FIXME: shall we do anything here on Windows?
226 return true;
227}
228
Timur Iskhodzhanov3e81fe42012-02-09 17:20:14 +0000229int AtomicInc(int *a) {
230 return InterlockedExchangeAdd((LONG*)a, 1) + 1;
231}
232
233const char* AsanGetEnv(const char* name) {
234 // FIXME: implement.
235 return NULL;
236}
237
Alexander Potapenko99d17eb2012-02-22 09:11:55 +0000238void AsanDumpProcessMap() {
239 UNIMPLEMENTED();
240}
241
Timur Iskhodzhanov3e81fe42012-02-09 17:20:14 +0000242int GetPid() {
243 return GetProcessId(GetCurrentProcess());
244}
245
246uintptr_t GetThreadSelf() {
247 return GetCurrentThreadId();
248}
249
250void InstallSignalHandlers() {
251 // FIXME: Decide what to do on Windows.
252}
253
254void AsanDisableCoreDumper() {
255 UNIMPLEMENTED();
256}
257
Kostya Serebryanye1fe0fd2012-02-13 21:24:29 +0000258void SleepForSeconds(int seconds) {
259 Sleep(seconds * 1000);
Timur Iskhodzhanov3e81fe42012-02-09 17:20:14 +0000260}
Kostya Serebryanye1fe0fd2012-02-13 21:24:29 +0000261
262void Exit(int exitcode) {
263 _exit(exitcode);
264}
Timur Iskhodzhanov3e81fe42012-02-09 17:20:14 +0000265
Alexey Samsonovb823e3c2012-02-22 14:07:06 +0000266int Atexit(void (*function)(void)) {
267 return atexit(function);
268}
269
Timur Iskhodzhanov3e81fe42012-02-09 17:20:14 +0000270} // namespace __asan
271
272#endif // _WIN32