blob: 61a0ede781e23b6b64399ffe561e6906814fe6a4 [file] [log] [blame]
Alexey Samsonov298dd7c2012-06-05 07:46:31 +00001//===-- sanitizer_win.cc --------------------------------------------------===//
Alexey Samsonovdde1f112012-06-05 07:05:10 +00002//
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 shared between AddressSanitizer and ThreadSanitizer
11// run-time libraries and implements windows-specific functions from
12// sanitizer_libc.h.
13//===----------------------------------------------------------------------===//
Evgeniy Stepanov0af67232013-03-19 14:33:38 +000014
15#include "sanitizer_platform.h"
16#if SANITIZER_WINDOWS
17
Dmitry Vyukov0ff6d2d2012-11-06 13:19:59 +000018#define WIN32_LEAN_AND_MEAN
19#define NOGDI
Alexey Samsonovdde1f112012-06-05 07:05:10 +000020#include <windows.h>
Timur Iskhodzhanov19853dd2014-07-11 11:57:41 +000021#include <dbghelp.h>
22#include <io.h>
Timur Iskhodzhanova04b33b2014-12-26 14:28:32 +000023#include <psapi.h>
Timur Iskhodzhanov19853dd2014-07-11 11:57:41 +000024#include <stdlib.h>
Alexey Samsonovdde1f112012-06-05 07:05:10 +000025
Alexey Samsonov201aa362012-06-06 09:43:32 +000026#include "sanitizer_common.h"
Alexey Samsonovdde1f112012-06-05 07:05:10 +000027#include "sanitizer_libc.h"
Dmitry Vyukovff198092013-01-14 14:28:06 +000028#include "sanitizer_mutex.h"
Sergey Matveevaf179b82013-05-08 12:45:55 +000029#include "sanitizer_placement_new.h"
30#include "sanitizer_stacktrace.h"
Alexey Samsonovdde1f112012-06-05 07:05:10 +000031
Alexey Samsonovdde1f112012-06-05 07:05:10 +000032namespace __sanitizer {
33
Peter Collingbourne6f4be192013-05-08 14:43:49 +000034#include "sanitizer_syscall_generic.inc"
35
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000036// --------------------- sanitizer_common.h
Kostya Serebryanyf22c6972012-11-23 15:38:49 +000037uptr GetPageSize() {
38 return 1U << 14; // FIXME: is this configurable?
39}
40
41uptr GetMmapGranularity() {
42 return 1U << 16; // FIXME: is this configurable?
43}
44
Timur Iskhodzhanov4245f782013-07-16 09:47:39 +000045uptr GetMaxVirtualAddress() {
46 SYSTEM_INFO si;
47 GetSystemInfo(&si);
48 return (uptr)si.lpMaximumApplicationAddress;
49}
50
Alexey Samsonovae9b18b2012-11-09 14:45:30 +000051bool FileExists(const char *filename) {
52 UNIMPLEMENTED();
53}
54
Peter Collingbourneffaf2ea2013-05-17 16:56:53 +000055uptr internal_getpid() {
Alexey Samsonovee072902012-06-06 09:26:25 +000056 return GetProcessId(GetCurrentProcess());
57}
58
Timur Iskhodzhanov2dee3dd2013-03-25 22:04:29 +000059// In contrast to POSIX, on Windows GetCurrentThreadId()
60// returns a system-unique identifier.
61uptr GetTid() {
Alexey Samsonov70afb912012-06-15 06:37:34 +000062 return GetCurrentThreadId();
63}
64
Timur Iskhodzhanov2dee3dd2013-03-25 22:04:29 +000065uptr GetThreadSelf() {
66 return GetTid();
67}
68
Dmitry Vyukovaa8fa602014-09-01 11:44:59 +000069#if !SANITIZER_GO
Alexey Samsonovcf4d3a02012-06-07 07:32:00 +000070void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000071 uptr *stack_bottom) {
72 CHECK(stack_top);
73 CHECK(stack_bottom);
74 MEMORY_BASIC_INFORMATION mbi;
Kostya Serebryany98390d02012-06-20 15:19:17 +000075 CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0);
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000076 // FIXME: is it possible for the stack to not be a single allocation?
77 // Are these values what ASan expects to get (reserved, not committed;
78 // including stack guard page) ?
79 *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize;
80 *stack_bottom = (uptr)mbi.AllocationBase;
81}
Dmitry Vyukovaa8fa602014-09-01 11:44:59 +000082#endif // #if !SANITIZER_GO
Alexey Samsonov4b1f1032012-06-07 07:13:46 +000083
Alexey Samsonov40d5b772012-06-06 16:15:07 +000084void *MmapOrDie(uptr size, const char *mem_type) {
Alexey Samsonovee072902012-06-06 09:26:25 +000085 void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
Alexey Samsonov40d5b772012-06-06 16:15:07 +000086 if (rv == 0) {
Timur Iskhodzhanov364b8b82014-03-19 08:23:00 +000087 Report("ERROR: %s failed to "
88 "allocate 0x%zx (%zd) bytes of %s (error code: %d)\n",
89 SanitizerToolName, size, size, mem_type, GetLastError());
Alexey Samsonov40d5b772012-06-06 16:15:07 +000090 CHECK("unable to mmap" && 0);
91 }
Alexey Samsonovee072902012-06-06 09:26:25 +000092 return rv;
93}
94
95void UnmapOrDie(void *addr, uptr size) {
Timur Iskhodzhanov89608af2015-03-31 16:39:20 +000096 if (!size || !addr)
97 return;
98
Alexey Samsonove95e29c2012-06-06 15:47:40 +000099 if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
Timur Iskhodzhanov364b8b82014-03-19 08:23:00 +0000100 Report("ERROR: %s failed to "
101 "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n",
102 SanitizerToolName, size, size, addr, GetLastError());
Alexey Samsonov40d5b772012-06-06 16:15:07 +0000103 CHECK("unable to unmap" && 0);
Alexey Samsonove95e29c2012-06-06 15:47:40 +0000104 }
Alexey Samsonovee072902012-06-06 09:26:25 +0000105}
106
Evgeniy Stepanov8e9c70b2015-05-29 22:31:28 +0000107void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) {
Kostya Serebryany98066282012-12-13 05:36:00 +0000108 // FIXME: is this really "NoReserve"? On Win32 this does not matter much,
109 // but on Win64 it does.
Evgeniy Stepanov8e9c70b2015-05-29 22:31:28 +0000110 (void)name; // unsupported
Dmitry Vyukov0ff6d2d2012-11-06 13:19:59 +0000111 void *p = VirtualAlloc((LPVOID)fixed_addr, size,
112 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
113 if (p == 0)
Timur Iskhodzhanov364b8b82014-03-19 08:23:00 +0000114 Report("ERROR: %s failed to "
115 "allocate %p (%zd) bytes at %p (error code: %d)\n",
116 SanitizerToolName, size, size, fixed_addr, GetLastError());
Dmitry Vyukov0ff6d2d2012-11-06 13:19:59 +0000117 return p;
Alexey Samsonovc70d1082012-06-14 14:42:58 +0000118}
119
Kostya Serebryany98066282012-12-13 05:36:00 +0000120void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
Kostya Serebryanya1670872012-12-13 05:51:02 +0000121 return MmapFixedNoReserve(fixed_addr, size);
Kostya Serebryany98066282012-12-13 05:36:00 +0000122}
123
Kostya Serebryany57bfdb02013-12-13 15:03:49 +0000124void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
125 // FIXME: make this really NoReserve?
126 return MmapOrDie(size, mem_type);
127}
128
Evgeniy Stepanov8e9c70b2015-05-29 22:31:28 +0000129void *MmapNoAccess(uptr fixed_addr, uptr size, const char *name) {
130 (void)name; // unsupported
Timur Iskhodzhanove5935ef2015-02-02 15:04:23 +0000131 void *res = VirtualAlloc((LPVOID)fixed_addr, size,
132 MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
133 if (res == 0)
134 Report("WARNING: %s failed to "
135 "mprotect %p (%zd) bytes at %p (error code: %d)\n",
136 SanitizerToolName, size, size, fixed_addr, GetLastError());
137 return res;
Alexey Samsonovc70d1082012-06-14 14:42:58 +0000138}
139
Timur Iskhodzhanovea1f3322015-04-10 15:02:19 +0000140bool MprotectNoAccess(uptr addr, uptr size) {
141 DWORD old_protection;
142 return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection);
143}
144
145
Timur Iskhodzhanov167f9e42013-02-08 12:02:00 +0000146void FlushUnneededShadowMemory(uptr addr, uptr size) {
147 // This is almost useless on 32-bits.
Yury Gribov8f848ff2015-02-03 10:15:15 +0000148 // FIXME: add madvise-analog when we move to 64-bits.
Timur Iskhodzhanov167f9e42013-02-08 12:02:00 +0000149}
150
Kostya Serebryanyc6338ac2015-01-21 02:05:31 +0000151void NoHugePagesInRegion(uptr addr, uptr size) {
152 // FIXME: probably similar to FlushUnneededShadowMemory.
153}
154
Yury Gribov8f848ff2015-02-03 10:15:15 +0000155void DontDumpShadowMemory(uptr addr, uptr length) {
156 // This is almost useless on 32-bits.
157 // FIXME: add madvise-analog when we move to 64-bits.
158}
159
Alexey Samsonov40e51282012-06-15 07:29:14 +0000160bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
Timur Iskhodzhanova04b33b2014-12-26 14:28:32 +0000161 MEMORY_BASIC_INFORMATION mbi;
162 CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi)));
Timur Iskhodzhanove5935ef2015-02-02 15:04:23 +0000163 return mbi.Protect == PAGE_NOACCESS &&
Timur Iskhodzhanova04b33b2014-12-26 14:28:32 +0000164 (uptr)mbi.BaseAddress + mbi.RegionSize >= range_end;
Alexey Samsonov40e51282012-06-15 07:29:14 +0000165}
166
Alexey Samsonov961276a2012-07-03 08:24:14 +0000167void *MapFileToMemory(const char *file_name, uptr *buff_size) {
168 UNIMPLEMENTED();
169}
170
Timur Iskhodzhanovdaa9e2d2015-04-08 16:03:22 +0000171void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, uptr offset) {
Evgeniy Stepanova00ff192014-05-28 08:26:24 +0000172 UNIMPLEMENTED();
173}
174
Alexey Samsonov7d238542013-03-14 11:29:06 +0000175static const int kMaxEnvNameLength = 128;
Dmitry Vyukove979c542013-06-10 10:02:02 +0000176static const DWORD kMaxEnvValueLength = 32767;
Alexey Samsonov83e76222013-03-14 11:10:23 +0000177
178namespace {
179
180struct EnvVariable {
181 char name[kMaxEnvNameLength];
182 char value[kMaxEnvValueLength];
183};
184
185} // namespace
186
187static const int kEnvVariables = 5;
188static EnvVariable env_vars[kEnvVariables];
189static int num_env_vars;
190
Alexey Samsonov0c53a382012-06-14 14:07:21 +0000191const char *GetEnv(const char *name) {
Alexey Samsonov83e76222013-03-14 11:10:23 +0000192 // Note: this implementation caches the values of the environment variables
193 // and limits their quantity.
194 for (int i = 0; i < num_env_vars; i++) {
195 if (0 == internal_strcmp(name, env_vars[i].name))
196 return env_vars[i].value;
197 }
198 CHECK_LT(num_env_vars, kEnvVariables);
199 DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value,
200 kMaxEnvValueLength);
201 if (rv > 0 && rv < kMaxEnvValueLength) {
202 CHECK_LT(internal_strlen(name), kMaxEnvNameLength);
203 internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength);
204 num_env_vars++;
205 return env_vars[num_env_vars - 1].value;
206 }
Alexey Samsonov0c53a382012-06-14 14:07:21 +0000207 return 0;
208}
209
Alexey Samsonov58a3c582012-06-18 08:44:30 +0000210const char *GetPwd() {
211 UNIMPLEMENTED();
212}
213
Alexey Samsonov9211bd32013-02-18 07:17:12 +0000214u32 GetUid() {
215 UNIMPLEMENTED();
216}
217
Timur Iskhodzhanov64fc8e42014-12-30 14:44:12 +0000218namespace {
219struct ModuleInfo {
Timur Iskhodzhanovb97bcc42015-04-06 12:49:30 +0000220 const char *filepath;
Timur Iskhodzhanov64fc8e42014-12-30 14:44:12 +0000221 uptr base_address;
222 uptr end_address;
223};
224
225int CompareModulesBase(const void *pl, const void *pr) {
Timur Iskhodzhanovb97bcc42015-04-06 12:49:30 +0000226 const ModuleInfo *l = (ModuleInfo *)pl, *r = (ModuleInfo *)pr;
227 if (l->base_address < r->base_address)
Timur Iskhodzhanov64fc8e42014-12-30 14:44:12 +0000228 return -1;
Timur Iskhodzhanovb97bcc42015-04-06 12:49:30 +0000229 return l->base_address > r->base_address;
Timur Iskhodzhanov64fc8e42014-12-30 14:44:12 +0000230}
Timur Iskhodzhanova023e062014-12-30 15:30:19 +0000231} // namespace
Timur Iskhodzhanov64fc8e42014-12-30 14:44:12 +0000232
Dmitry Vyukovb3381fa2015-02-16 13:51:17 +0000233#ifndef SANITIZER_GO
Alexey Samsonovae1e1712012-06-15 06:08:19 +0000234void DumpProcessMap() {
Timur Iskhodzhanova04b33b2014-12-26 14:28:32 +0000235 Report("Dumping process modules:\n");
Timur Iskhodzhanovb97bcc42015-04-06 12:49:30 +0000236 InternalScopedBuffer<LoadedModule> modules(kMaxNumberOfModules);
237 uptr num_modules =
238 GetListOfModules(modules.data(), kMaxNumberOfModules, nullptr);
Timur Iskhodzhanova04b33b2014-12-26 14:28:32 +0000239
Timur Iskhodzhanovb97bcc42015-04-06 12:49:30 +0000240 InternalScopedBuffer<ModuleInfo> module_infos(num_modules);
241 for (size_t i = 0; i < num_modules; ++i) {
242 module_infos[i].filepath = modules[i].full_name();
243 module_infos[i].base_address = modules[i].base_address();
244 module_infos[i].end_address = modules[i].ranges().next()->end;
Timur Iskhodzhanova04b33b2014-12-26 14:28:32 +0000245 }
Timur Iskhodzhanovb97bcc42015-04-06 12:49:30 +0000246 qsort(module_infos.data(), num_modules, sizeof(ModuleInfo),
247 CompareModulesBase);
Timur Iskhodzhanov64fc8e42014-12-30 14:44:12 +0000248
249 for (size_t i = 0; i < num_modules; ++i) {
Timur Iskhodzhanovb97bcc42015-04-06 12:49:30 +0000250 const ModuleInfo &mi = module_infos[i];
Timur Iskhodzhanov64fc8e42014-12-30 14:44:12 +0000251 if (mi.end_address != 0) {
252 Printf("\t%p-%p %s\n", mi.base_address, mi.end_address,
Timur Iskhodzhanovb97bcc42015-04-06 12:49:30 +0000253 mi.filepath[0] ? mi.filepath : "[no name]");
Timur Iskhodzhanov1931b622015-04-06 12:54:06 +0000254 } else if (mi.filepath[0]) {
Timur Iskhodzhanovb97bcc42015-04-06 12:49:30 +0000255 Printf("\t??\?-??? %s\n", mi.filepath);
Timur Iskhodzhanova04b33b2014-12-26 14:28:32 +0000256 } else {
257 Printf("\t???\n");
258 }
259 }
Alexey Samsonovae1e1712012-06-15 06:08:19 +0000260}
Dmitry Vyukovb3381fa2015-02-16 13:51:17 +0000261#endif
Alexey Samsonovae1e1712012-06-15 06:08:19 +0000262
Alexey Samsonov34e2b282014-08-12 22:31:19 +0000263void DisableCoreDumperIfNecessary() {
Timur Iskhodzhanov7d5c81d2014-05-06 08:21:50 +0000264 // Do nothing.
Alexey Samsonovae1e1712012-06-15 06:08:19 +0000265}
266
Alexey Samsonov97ca3062012-09-17 09:12:39 +0000267void ReExec() {
268 UNIMPLEMENTED();
269}
270
Sergey Matveev6cb47a082014-05-19 12:53:03 +0000271void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
Timur Iskhodzhanovd0be0a92015-04-23 12:58:11 +0000272#if !SANITIZER_GO
273 CovPrepareForSandboxing(args);
274#endif
Alexander Potapenko1746f552012-12-10 13:10:40 +0000275}
276
Alexey Samsonov97ca3062012-09-17 09:12:39 +0000277bool StackSizeIsUnlimited() {
278 UNIMPLEMENTED();
Alexey Samsonov97ca3062012-09-17 09:12:39 +0000279}
280
281void SetStackSizeLimitInBytes(uptr limit) {
282 UNIMPLEMENTED();
283}
284
Alexey Samsonov34e2b282014-08-12 22:31:19 +0000285bool AddressSpaceIsUnlimited() {
286 UNIMPLEMENTED();
287}
288
289void SetAddressSpaceUnlimited() {
290 UNIMPLEMENTED();
291}
292
Alexey Samsonovde647dd2013-09-03 13:20:48 +0000293char *FindPathToBinary(const char *name) {
Timur Iskhodzhanov2eea5892013-09-03 15:50:13 +0000294 // Nothing here for now.
295 return 0;
Alexey Samsonovde647dd2013-09-03 13:20:48 +0000296}
297
Anna Zaks22490492015-02-27 03:12:19 +0000298uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
299 // Nothing here for now.
300 return 0;
301}
302
303bool IsPathSeparator(const char c) {
304 return c == '\\' || c == '/';
305}
306
307bool IsAbsolutePath(const char *path) {
308 UNIMPLEMENTED();
309}
310
Alexey Samsonov70afb912012-06-15 06:37:34 +0000311void SleepForSeconds(int seconds) {
312 Sleep(seconds * 1000);
313}
314
Alexey Samsonov58a3c582012-06-18 08:44:30 +0000315void SleepForMillis(int millis) {
316 Sleep(millis);
317}
318
Dmitry Vyukove979c542013-06-10 10:02:02 +0000319u64 NanoTime() {
320 return 0;
321}
322
Alexey Samsonov70afb912012-06-15 06:37:34 +0000323void Abort() {
Timur Iskhodzhanovb8373bc2014-12-26 12:25:54 +0000324 if (::IsDebuggerPresent())
325 __debugbreak();
326 internal__exit(3);
Alexey Samsonov70afb912012-06-15 06:37:34 +0000327}
328
Alexey Samsonov7a36e612013-09-10 14:36:16 +0000329uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
330 string_predicate_t filter) {
Timur Iskhodzhanovb97bcc42015-04-06 12:49:30 +0000331 HANDLE cur_process = GetCurrentProcess();
332
333 // Query the list of modules. Start by assuming there are no more than 256
334 // modules and retry if that's not sufficient.
335 HMODULE *hmodules = 0;
336 uptr modules_buffer_size = sizeof(HMODULE) * 256;
337 DWORD bytes_required;
338 while (!hmodules) {
339 hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__);
340 CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size,
341 &bytes_required));
342 if (bytes_required > modules_buffer_size) {
343 // Either there turned out to be more than 256 hmodules, or new hmodules
344 // could have loaded since the last try. Retry.
345 UnmapOrDie(hmodules, modules_buffer_size);
346 hmodules = 0;
347 modules_buffer_size = bytes_required;
348 }
349 }
350
351 // |num_modules| is the number of modules actually present,
352 // |count| is the number of modules we return.
353 size_t nun_modules = bytes_required / sizeof(HMODULE),
354 count = 0;
355 for (size_t i = 0; i < nun_modules && count < max_modules; ++i) {
356 HMODULE handle = hmodules[i];
357 MODULEINFO mi;
358 if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi)))
359 continue;
360
361 char module_name[MAX_PATH];
362 bool got_module_name =
363 GetModuleFileNameA(handle, module_name, sizeof(module_name));
364 if (!got_module_name)
365 module_name[0] = '\0';
366
367 if (filter && !filter(module_name))
368 continue;
369
370 uptr base_address = (uptr)mi.lpBaseOfDll;
371 uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage;
372 LoadedModule *cur_module = &modules[count];
373 cur_module->set(module_name, base_address);
374 // We add the whole module as one single address range.
375 cur_module->addAddressRange(base_address, end_address, /*executable*/ true);
376 count++;
377 }
378 UnmapOrDie(hmodules, modules_buffer_size);
379
380 return count;
Alexey Samsonov7a36e612013-09-10 14:36:16 +0000381};
382
Dmitry Vyukov0ff6d2d2012-11-06 13:19:59 +0000383#ifndef SANITIZER_GO
Timur Iskhodzhanovad3ec822015-04-02 14:48:08 +0000384// We can't use atexit() directly at __asan_init time as the CRT is not fully
385// initialized at this point. Place the functions into a vector and use
386// atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers).
387InternalMmapVectorNoCtor<void (*)(void)> atexit_functions;
388
Alexey Samsonov70afb912012-06-15 06:37:34 +0000389int Atexit(void (*function)(void)) {
Timur Iskhodzhanovad3ec822015-04-02 14:48:08 +0000390 atexit_functions.push_back(function);
391 return 0;
Alexey Samsonov70afb912012-06-15 06:37:34 +0000392}
Timur Iskhodzhanovad3ec822015-04-02 14:48:08 +0000393
394static int RunAtexit() {
395 int ret = 0;
396 for (uptr i = 0; i < atexit_functions.size(); ++i) {
397 ret |= atexit(atexit_functions[i]);
398 }
399 return ret;
400}
401
402#pragma section(".CRT$XID", long, read) // NOLINT
403static __declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit;
Dmitry Vyukov0ff6d2d2012-11-06 13:19:59 +0000404#endif
Alexey Samsonov70afb912012-06-15 06:37:34 +0000405
Alexey Samsonov4b1f1032012-06-07 07:13:46 +0000406// ------------------ sanitizer_libc.h
Timur Iskhodzhanov864308a2015-04-09 12:37:05 +0000407fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) {
Timur Iskhodzhanov007435c2015-04-09 15:25:21 +0000408 if (mode != WrOnly)
409 UNIMPLEMENTED();
410 fd_t res = CreateFile(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
411 FILE_ATTRIBUTE_NORMAL, nullptr);
412 CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd);
413 CHECK(res != kStderrFd || kStderrFd == kInvalidFd);
Timur Iskhodzhanov8a673682015-04-23 12:57:29 +0000414 if (res == kInvalidFd && last_error)
415 *last_error = GetLastError();
Timur Iskhodzhanov007435c2015-04-09 15:25:21 +0000416 return res;
Alexey Samsonov03c8b842012-06-05 08:32:53 +0000417}
418
Timur Iskhodzhanov864308a2015-04-09 12:37:05 +0000419void CloseFile(fd_t fd) {
Timur Iskhodzhanov007435c2015-04-09 15:25:21 +0000420 CloseHandle(fd);
Alexey Samsonovdde1f112012-06-05 07:05:10 +0000421}
422
Timur Iskhodzhanov2b391692015-04-09 13:38:14 +0000423bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
424 error_t *error_p) {
425 UNIMPLEMENTED();
426}
427
Timur Iskhodzhanovc2c9ea52015-04-08 17:42:57 +0000428bool SupportsColoredOutput(fd_t fd) {
429 // FIXME: support colored output.
430 return false;
431}
432
Timur Iskhodzhanove8a6fbb2015-04-09 14:11:25 +0000433bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
434 error_t *error_p) {
Timur Iskhodzhanov007435c2015-04-09 15:25:21 +0000435 CHECK(fd != kInvalidFd);
Timur Iskhodzhanovaeefb6a2014-02-04 23:28:30 +0000436
Timur Iskhodzhanov007435c2015-04-09 15:25:21 +0000437 if (fd == kStdoutFd) {
438 fd = GetStdHandle(STD_OUTPUT_HANDLE);
439 if (fd == 0) fd = kInvalidFd;
440 } else if (fd == kStderrFd) {
441 fd = GetStdHandle(STD_ERROR_HANDLE);
442 if (fd == 0) fd = kInvalidFd;
Timur Iskhodzhanovaeefb6a2014-02-04 23:28:30 +0000443 }
444
Timur Iskhodzhanove8a6fbb2015-04-09 14:11:25 +0000445 DWORD internal_bytes_written;
Timur Iskhodzhanov007435c2015-04-09 15:25:21 +0000446 if (fd == kInvalidFd ||
447 WriteFile(fd, buff, buff_size, &internal_bytes_written, 0)) {
448 if (error_p) *error_p = GetLastError();
449 return false;
450 } else {
Timur Iskhodzhanove8a6fbb2015-04-09 14:11:25 +0000451 if (bytes_written) *bytes_written = internal_bytes_written;
452 return true;
453 }
Alexey Samsonov03c8b842012-06-05 08:32:53 +0000454}
455
Timur Iskhodzhanova6600a92015-04-09 14:45:17 +0000456bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) {
457 UNIMPLEMENTED();
458}
459
Peter Collingbourne6f4be192013-05-08 14:43:49 +0000460uptr internal_sched_yield() {
Dmitry Vyukov0ff6d2d2012-11-06 13:19:59 +0000461 Sleep(0);
462 return 0;
Alexey Samsonov58a3c582012-06-18 08:44:30 +0000463}
464
Alexey Samsonovaadd1f22013-02-20 13:54:32 +0000465void internal__exit(int exitcode) {
Timur Iskhodzhanov895392d2013-11-26 09:40:39 +0000466 ExitProcess(exitcode);
Alexey Samsonovaadd1f22013-02-20 13:54:32 +0000467}
468
Evgeniy Stepanova00ff192014-05-28 08:26:24 +0000469uptr internal_ftruncate(fd_t fd, uptr size) {
470 UNIMPLEMENTED();
471}
472
Kostya Serebryany6c54a6b2014-12-09 01:22:59 +0000473uptr GetRSS() {
474 return 0;
475}
476
Kostya Serebryany43eb7732014-12-16 19:13:01 +0000477void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; }
Hans Wennborg7dd94572014-12-16 20:46:05 +0000478void internal_join_thread(void *th) { }
Kostya Serebryany43eb7732014-12-16 19:13:01 +0000479
Dmitry Vyukovf22982b2013-01-14 07:51:39 +0000480// ---------------------- BlockingMutex ---------------- {{{1
Dmitry Vyukovfa67ed42013-02-04 10:42:38 +0000481const uptr LOCK_UNINITIALIZED = 0;
482const uptr LOCK_READY = (uptr)-1;
Dmitry Vyukovf22982b2013-01-14 07:51:39 +0000483
484BlockingMutex::BlockingMutex(LinkerInitialized li) {
485 // FIXME: see comments in BlockingMutex::Lock() for the details.
486 CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);
487
488 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
489 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
490 owner_ = LOCK_READY;
491}
492
Alexey Samsonova097f7b2013-03-14 13:30:56 +0000493BlockingMutex::BlockingMutex() {
494 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
495 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
496 owner_ = LOCK_READY;
497}
498
Dmitry Vyukovf22982b2013-01-14 07:51:39 +0000499void BlockingMutex::Lock() {
500 if (owner_ == LOCK_UNINITIALIZED) {
501 // FIXME: hm, global BlockingMutex objects are not initialized?!?
502 // This might be a side effect of the clang+cl+link Frankenbuild...
503 new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1));
504
505 // FIXME: If it turns out the linker doesn't invoke our
506 // constructors, we should probably manually Lock/Unlock all the global
507 // locks while we're starting in one thread to avoid double-init races.
508 }
509 EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
Dmitry Vyukov7981ea82013-02-04 08:07:45 +0000510 CHECK_EQ(owner_, LOCK_READY);
Dmitry Vyukovf22982b2013-01-14 07:51:39 +0000511 owner_ = GetThreadSelf();
512}
513
514void BlockingMutex::Unlock() {
Dmitry Vyukov7981ea82013-02-04 08:07:45 +0000515 CHECK_EQ(owner_, GetThreadSelf());
Dmitry Vyukovf22982b2013-01-14 07:51:39 +0000516 owner_ = LOCK_READY;
517 LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
518}
519
Alexey Samsonovdb7d9652013-03-11 15:45:20 +0000520void BlockingMutex::CheckLocked() {
521 CHECK_EQ(owner_, GetThreadSelf());
522}
523
Evgeniy Stepanov5697b582013-03-13 08:19:53 +0000524uptr GetTlsSize() {
525 return 0;
526}
527
528void InitTlsSize() {
529}
530
Sergey Matveev954c6ef12013-05-07 14:41:43 +0000531void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
532 uptr *tls_addr, uptr *tls_size) {
Dmitry Vyukovb278f122013-06-10 10:30:54 +0000533#ifdef SANITIZER_GO
534 *stk_addr = 0;
535 *stk_size = 0;
536 *tls_addr = 0;
537 *tls_size = 0;
538#else
Sergey Matveev954c6ef12013-05-07 14:41:43 +0000539 uptr stack_top, stack_bottom;
540 GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
541 *stk_addr = stack_bottom;
542 *stk_size = stack_top - stack_bottom;
543 *tls_addr = 0;
544 *tls_size = 0;
Dmitry Vyukovb278f122013-06-10 10:30:54 +0000545#endif
Sergey Matveev954c6ef12013-05-07 14:41:43 +0000546}
547
Dmitry Vyukovaa8fa602014-09-01 11:44:59 +0000548#if !SANITIZER_GO
Evgeniy Stepanov8eb82042015-01-22 13:47:12 +0000549void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) {
Alexey Samsonov3e8467b2014-03-04 12:21:28 +0000550 CHECK_GE(max_depth, 2);
Sergey Matveevaf179b82013-05-08 12:45:55 +0000551 // FIXME: CaptureStackBackTrace might be too slow for us.
552 // FIXME: Compare with StackWalk64.
553 // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
Timur Iskhodzhanov1f1c7ec2013-11-09 13:59:12 +0000554 size = CaptureStackBackTrace(2, Min(max_depth, kStackTraceMax),
555 (void**)trace, 0);
Timur Iskhodzhanov89a346c2013-12-10 08:30:39 +0000556 if (size == 0)
557 return;
558
Sergey Matveevaf179b82013-05-08 12:45:55 +0000559 // Skip the RTL frames by searching for the PC in the stacktrace.
Timur Iskhodzhanov1f1c7ec2013-11-09 13:59:12 +0000560 uptr pc_location = LocatePcInTrace(pc);
561 PopStackFrames(pc_location);
Sergey Matveevaf179b82013-05-08 12:45:55 +0000562}
563
Alexey Samsonov9c859272014-10-26 03:35:14 +0000564void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
Evgeniy Stepanov8eb82042015-01-22 13:47:12 +0000565 u32 max_depth) {
Timur Iskhodzhanov19853dd2014-07-11 11:57:41 +0000566 CONTEXT ctx = *(CONTEXT *)context;
567 STACKFRAME64 stack_frame;
568 memset(&stack_frame, 0, sizeof(stack_frame));
569 size = 0;
570#if defined(_WIN64)
571 int machine_type = IMAGE_FILE_MACHINE_AMD64;
572 stack_frame.AddrPC.Offset = ctx.Rip;
573 stack_frame.AddrFrame.Offset = ctx.Rbp;
574 stack_frame.AddrStack.Offset = ctx.Rsp;
575#else
576 int machine_type = IMAGE_FILE_MACHINE_I386;
577 stack_frame.AddrPC.Offset = ctx.Eip;
578 stack_frame.AddrFrame.Offset = ctx.Ebp;
579 stack_frame.AddrStack.Offset = ctx.Esp;
580#endif
581 stack_frame.AddrPC.Mode = AddrModeFlat;
582 stack_frame.AddrFrame.Mode = AddrModeFlat;
583 stack_frame.AddrStack.Mode = AddrModeFlat;
584 while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(),
585 &stack_frame, &ctx, NULL, &SymFunctionTableAccess64,
586 &SymGetModuleBase64, NULL) &&
587 size < Min(max_depth, kStackTraceMax)) {
Hans Wennborgf89a3f862014-10-26 19:27:02 +0000588 trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
Timur Iskhodzhanov19853dd2014-07-11 11:57:41 +0000589 }
Evgeniy Stepanove5a447d2014-02-11 13:57:17 +0000590}
Dmitry Vyukovaa8fa602014-09-01 11:44:59 +0000591#endif // #if !SANITIZER_GO
Evgeniy Stepanove5a447d2014-02-11 13:57:17 +0000592
Alexey Samsonov3a41ed12014-12-11 18:30:25 +0000593void ReportFile::Write(const char *buffer, uptr length) {
594 SpinMutexLock l(mu);
595 ReopenIfNecessary();
Timur Iskhodzhanove8a6fbb2015-04-09 14:11:25 +0000596 if (!WriteToFile(fd, buffer, length)) {
Reid Klecknerd483c072013-09-05 03:19:57 +0000597 // stderr may be closed, but we may be able to print to the debugger
598 // instead. This is the case when launching a program from Visual Studio,
599 // and the following routine should write to its console.
600 OutputDebugStringA(buffer);
601 }
602}
603
Alexander Potapenkod8d490e2014-01-28 11:12:29 +0000604void SetAlternateSignalStack() {
605 // FIXME: Decide what to do on Windows.
606}
607
608void UnsetAlternateSignalStack() {
609 // FIXME: Decide what to do on Windows.
610}
611
Alexander Potapenkoea4a0db2014-01-31 15:11:11 +0000612void InstallDeadlySignalHandlers(SignalHandlerType handler) {
613 (void)handler;
Alexander Potapenko789e3e12014-01-31 13:10:07 +0000614 // FIXME: Decide what to do on Windows.
615}
616
617bool IsDeadlySignal(int signum) {
618 // FIXME: Decide what to do on Windows.
619 return false;
620}
621
Alexey Samsonov1947bf92014-09-17 17:56:15 +0000622bool IsAccessibleMemoryRange(uptr beg, uptr size) {
623 // FIXME: Actually implement this function.
624 return true;
625}
626
Dmitry Vyukovdf01bdc2015-03-02 17:45:18 +0000627SignalContext SignalContext::Create(void *siginfo, void *context) {
628 EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD*)siginfo;
629 CONTEXT *context_record = (CONTEXT*)context;
630
631 uptr pc = (uptr)exception_record->ExceptionAddress;
632#ifdef _WIN64
633 uptr bp = (uptr)context_record->Rbp;
634 uptr sp = (uptr)context_record->Rsp;
635#else
636 uptr bp = (uptr)context_record->Ebp;
637 uptr sp = (uptr)context_record->Esp;
638#endif
639 uptr access_addr = exception_record->ExceptionInformation[1];
640
641 return SignalContext(context, access_addr, pc, sp, bp);
642}
643
Yury Gribovc019a572015-06-04 07:29:43 +0000644uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
645 // FIXME: Actually implement this function.
646 CHECK_GT(buf_len, 0);
647 buf[0] = 0;
648 return 0;
649}
650
Alexey Samsonovdde1f112012-06-05 07:05:10 +0000651} // namespace __sanitizer
652
653#endif // _WIN32