blob: 94393c4ef9dce29d5293c6974d82b9eaacaf1a61 [file] [log] [blame]
Alexey Samsonov7f9c5a22012-06-05 07:46:31 +00001//===-- sanitizer_win.cc --------------------------------------------------===//
Alexey Samsonovc5d46512012-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 Stepanov24e13722013-03-19 14:33:38 +000014
15#include "sanitizer_platform.h"
16#if SANITIZER_WINDOWS
17
Dmitry Vyukov33b2a942012-11-06 13:19:59 +000018#define WIN32_LEAN_AND_MEAN
19#define NOGDI
Alexey Samsonovc5d46512012-06-05 07:05:10 +000020#include <windows.h>
Stephen Hines6d186232014-11-26 17:56:19 -080021#include <dbghelp.h>
22#include <io.h>
Stephen Hines86277eb2015-03-23 12:06:32 -070023#include <psapi.h>
Stephen Hines6d186232014-11-26 17:56:19 -080024#include <stdlib.h>
Alexey Samsonovc5d46512012-06-05 07:05:10 +000025
Alexey Samsonov9929ffd2012-06-06 09:43:32 +000026#include "sanitizer_common.h"
Alexey Samsonovc5d46512012-06-05 07:05:10 +000027#include "sanitizer_libc.h"
Dmitry Vyukov53833ea2013-01-14 14:28:06 +000028#include "sanitizer_mutex.h"
Sergey Matveev736cf492013-05-08 12:45:55 +000029#include "sanitizer_placement_new.h"
30#include "sanitizer_stacktrace.h"
Alexey Samsonovc5d46512012-06-05 07:05:10 +000031
Alexey Samsonovc5d46512012-06-05 07:05:10 +000032namespace __sanitizer {
33
Peter Collingbourne9578a3e2013-05-08 14:43:49 +000034#include "sanitizer_syscall_generic.inc"
35
Alexey Samsonove5931fd2012-06-07 07:13:46 +000036// --------------------- sanitizer_common.h
Kostya Serebryanyf67ec2b2012-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 Iskhodzhanovbb7f2d82013-07-16 09:47:39 +000045uptr GetMaxVirtualAddress() {
46 SYSTEM_INFO si;
47 GetSystemInfo(&si);
48 return (uptr)si.lpMaximumApplicationAddress;
49}
50
Alexey Samsonov93b4caf2012-11-09 14:45:30 +000051bool FileExists(const char *filename) {
52 UNIMPLEMENTED();
53}
54
Peter Collingbourne0b694fc2013-05-17 16:56:53 +000055uptr internal_getpid() {
Alexey Samsonov230c3be2012-06-06 09:26:25 +000056 return GetProcessId(GetCurrentProcess());
57}
58
Timur Iskhodzhanov2c969872013-03-25 22:04:29 +000059// In contrast to POSIX, on Windows GetCurrentThreadId()
60// returns a system-unique identifier.
61uptr GetTid() {
Alexey Samsonovfa3daaf2012-06-15 06:37:34 +000062 return GetCurrentThreadId();
63}
64
Timur Iskhodzhanov2c969872013-03-25 22:04:29 +000065uptr GetThreadSelf() {
66 return GetTid();
67}
68
Stephen Hines6d186232014-11-26 17:56:19 -080069#if !SANITIZER_GO
Alexey Samsonoved996f72012-06-07 07:32:00 +000070void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
Alexey Samsonove5931fd2012-06-07 07:13:46 +000071 uptr *stack_bottom) {
72 CHECK(stack_top);
73 CHECK(stack_bottom);
74 MEMORY_BASIC_INFORMATION mbi;
Kostya Serebryany69850852012-06-20 15:19:17 +000075 CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0);
Alexey Samsonove5931fd2012-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}
Stephen Hines6d186232014-11-26 17:56:19 -080082#endif // #if !SANITIZER_GO
Alexey Samsonove5931fd2012-06-07 07:13:46 +000083
Alexey Samsonova25b3462012-06-06 16:15:07 +000084void *MmapOrDie(uptr size, const char *mem_type) {
Alexey Samsonov230c3be2012-06-06 09:26:25 +000085 void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
Alexey Samsonova25b3462012-06-06 16:15:07 +000086 if (rv == 0) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -070087 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 Samsonova25b3462012-06-06 16:15:07 +000090 CHECK("unable to mmap" && 0);
91 }
Alexey Samsonov230c3be2012-06-06 09:26:25 +000092 return rv;
93}
94
95void UnmapOrDie(void *addr, uptr size) {
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -070096 if (!size || !addr)
97 return;
98
Alexey Samsonov8c53e542012-06-06 15:47:40 +000099 if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700100 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 Samsonova25b3462012-06-06 16:15:07 +0000103 CHECK("unable to unmap" && 0);
Alexey Samsonov8c53e542012-06-06 15:47:40 +0000104 }
Alexey Samsonov230c3be2012-06-06 09:26:25 +0000105}
106
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -0700107void *MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) {
Kostya Serebryany9bfe78f2012-12-13 05:36:00 +0000108 // FIXME: is this really "NoReserve"? On Win32 this does not matter much,
109 // but on Win64 it does.
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -0700110 (void)name; // unsupported
Dmitry Vyukov33b2a942012-11-06 13:19:59 +0000111 void *p = VirtualAlloc((LPVOID)fixed_addr, size,
112 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
113 if (p == 0)
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700114 Report("ERROR: %s failed to "
115 "allocate %p (%zd) bytes at %p (error code: %d)\n",
116 SanitizerToolName, size, size, fixed_addr, GetLastError());
Dmitry Vyukov33b2a942012-11-06 13:19:59 +0000117 return p;
Alexey Samsonovf607fc12012-06-14 14:42:58 +0000118}
119
Kostya Serebryany9bfe78f2012-12-13 05:36:00 +0000120void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
Kostya Serebryany8c58aa72012-12-13 05:51:02 +0000121 return MmapFixedNoReserve(fixed_addr, size);
Kostya Serebryany9bfe78f2012-12-13 05:36:00 +0000122}
123
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700124void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
125 // FIXME: make this really NoReserve?
126 return MmapOrDie(size, mem_type);
127}
128
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -0700129void *MmapNoAccess(uptr fixed_addr, uptr size, const char *name) {
130 (void)name; // unsupported
Stephen Hines86277eb2015-03-23 12:06:32 -0700131 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 Samsonovf607fc12012-06-14 14:42:58 +0000138}
139
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700140bool MprotectNoAccess(uptr addr, uptr size) {
141 DWORD old_protection;
142 return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection);
143}
144
145
Timur Iskhodzhanov2b10d392013-02-08 12:02:00 +0000146void FlushUnneededShadowMemory(uptr addr, uptr size) {
147 // This is almost useless on 32-bits.
Stephen Hines86277eb2015-03-23 12:06:32 -0700148 // FIXME: add madvise-analog when we move to 64-bits.
149}
150
151void NoHugePagesInRegion(uptr addr, uptr size) {
152 // FIXME: probably similar to FlushUnneededShadowMemory.
153}
154
155void DontDumpShadowMemory(uptr addr, uptr length) {
156 // This is almost useless on 32-bits.
157 // FIXME: add madvise-analog when we move to 64-bits.
Timur Iskhodzhanov2b10d392013-02-08 12:02:00 +0000158}
159
Alexey Samsonovdd3a9112012-06-15 07:29:14 +0000160bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
Stephen Hines86277eb2015-03-23 12:06:32 -0700161 MEMORY_BASIC_INFORMATION mbi;
162 CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi)));
163 return mbi.Protect == PAGE_NOACCESS &&
164 (uptr)mbi.BaseAddress + mbi.RegionSize >= range_end;
Alexey Samsonovdd3a9112012-06-15 07:29:14 +0000165}
166
Alexey Samsonova68633f2012-07-03 08:24:14 +0000167void *MapFileToMemory(const char *file_name, uptr *buff_size) {
168 UNIMPLEMENTED();
169}
170
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700171void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, uptr offset) {
Stephen Hines6a211c52014-07-21 00:49:56 -0700172 UNIMPLEMENTED();
173}
174
Alexey Samsonova3ab1922013-03-14 11:29:06 +0000175static const int kMaxEnvNameLength = 128;
Dmitry Vyukovc5288672013-06-10 10:02:02 +0000176static const DWORD kMaxEnvValueLength = 32767;
Alexey Samsonov1ef94b12013-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 Samsonov3dbeabb2012-06-14 14:07:21 +0000191const char *GetEnv(const char *name) {
Alexey Samsonov1ef94b12013-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 Samsonov3dbeabb2012-06-14 14:07:21 +0000207 return 0;
208}
209
Alexey Samsonov0969bcf2012-06-18 08:44:30 +0000210const char *GetPwd() {
211 UNIMPLEMENTED();
212}
213
Alexey Samsonov0fa691b2013-02-18 07:17:12 +0000214u32 GetUid() {
215 UNIMPLEMENTED();
216}
217
Stephen Hines86277eb2015-03-23 12:06:32 -0700218namespace {
219struct ModuleInfo {
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700220 const char *filepath;
Stephen Hines86277eb2015-03-23 12:06:32 -0700221 uptr base_address;
222 uptr end_address;
223};
224
225int CompareModulesBase(const void *pl, const void *pr) {
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700226 const ModuleInfo *l = (ModuleInfo *)pl, *r = (ModuleInfo *)pr;
227 if (l->base_address < r->base_address)
Stephen Hines86277eb2015-03-23 12:06:32 -0700228 return -1;
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700229 return l->base_address > r->base_address;
Alexey Samsonovbe7420c2012-06-15 06:08:19 +0000230}
Stephen Hines86277eb2015-03-23 12:06:32 -0700231} // namespace
232
233#ifndef SANITIZER_GO
234void DumpProcessMap() {
235 Report("Dumping process modules:\n");
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700236 InternalScopedBuffer<LoadedModule> modules(kMaxNumberOfModules);
237 uptr num_modules =
238 GetListOfModules(modules.data(), kMaxNumberOfModules, nullptr);
Stephen Hines86277eb2015-03-23 12:06:32 -0700239
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700240 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;
Stephen Hines86277eb2015-03-23 12:06:32 -0700245 }
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700246 qsort(module_infos.data(), num_modules, sizeof(ModuleInfo),
247 CompareModulesBase);
Stephen Hines86277eb2015-03-23 12:06:32 -0700248
249 for (size_t i = 0; i < num_modules; ++i) {
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700250 const ModuleInfo &mi = module_infos[i];
Stephen Hines86277eb2015-03-23 12:06:32 -0700251 if (mi.end_address != 0) {
252 Printf("\t%p-%p %s\n", mi.base_address, mi.end_address,
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700253 mi.filepath[0] ? mi.filepath : "[no name]");
254 } else if (mi.filepath[0]) {
255 Printf("\t??\?-??? %s\n", mi.filepath);
Stephen Hines86277eb2015-03-23 12:06:32 -0700256 } else {
257 Printf("\t???\n");
258 }
259 }
Stephen Hines86277eb2015-03-23 12:06:32 -0700260}
261#endif
Alexey Samsonovbe7420c2012-06-15 06:08:19 +0000262
Stephen Hines6d186232014-11-26 17:56:19 -0800263void DisableCoreDumperIfNecessary() {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700264 // Do nothing.
Alexey Samsonovbe7420c2012-06-15 06:08:19 +0000265}
266
Alexey Samsonovd7e5bb42012-09-17 09:12:39 +0000267void ReExec() {
268 UNIMPLEMENTED();
269}
270
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700271void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -0700272#if !SANITIZER_GO
273 CovPrepareForSandboxing(args);
274#endif
Alexander Potapenko25742572012-12-10 13:10:40 +0000275}
276
Alexey Samsonovd7e5bb42012-09-17 09:12:39 +0000277bool StackSizeIsUnlimited() {
278 UNIMPLEMENTED();
Alexey Samsonovd7e5bb42012-09-17 09:12:39 +0000279}
280
281void SetStackSizeLimitInBytes(uptr limit) {
282 UNIMPLEMENTED();
283}
284
Stephen Hines6d186232014-11-26 17:56:19 -0800285bool AddressSpaceIsUnlimited() {
286 UNIMPLEMENTED();
287}
288
289void SetAddressSpaceUnlimited() {
290 UNIMPLEMENTED();
291}
292
Alexey Samsonov1dcd1d92013-09-03 13:20:48 +0000293char *FindPathToBinary(const char *name) {
Timur Iskhodzhanov5a58ef42013-09-03 15:50:13 +0000294 // Nothing here for now.
295 return 0;
Alexey Samsonov1dcd1d92013-09-03 13:20:48 +0000296}
297
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700298bool IsPathSeparator(const char c) {
299 return c == '\\' || c == '/';
300}
301
302bool IsAbsolutePath(const char *path) {
303 UNIMPLEMENTED();
304}
305
Alexey Samsonovfa3daaf2012-06-15 06:37:34 +0000306void SleepForSeconds(int seconds) {
307 Sleep(seconds * 1000);
308}
309
Alexey Samsonov0969bcf2012-06-18 08:44:30 +0000310void SleepForMillis(int millis) {
311 Sleep(millis);
312}
313
Dmitry Vyukovc5288672013-06-10 10:02:02 +0000314u64 NanoTime() {
315 return 0;
316}
317
Alexey Samsonovfa3daaf2012-06-15 06:37:34 +0000318void Abort() {
Stephen Hines86277eb2015-03-23 12:06:32 -0700319 if (::IsDebuggerPresent())
320 __debugbreak();
321 internal__exit(3);
Alexey Samsonovfa3daaf2012-06-15 06:37:34 +0000322}
323
Alexey Samsonov7847d772013-09-10 14:36:16 +0000324uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
325 string_predicate_t filter) {
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700326 HANDLE cur_process = GetCurrentProcess();
Alexey Samsonov7847d772013-09-10 14:36:16 +0000327
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700328 // Query the list of modules. Start by assuming there are no more than 256
329 // modules and retry if that's not sufficient.
330 HMODULE *hmodules = 0;
331 uptr modules_buffer_size = sizeof(HMODULE) * 256;
332 DWORD bytes_required;
333 while (!hmodules) {
334 hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__);
335 CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size,
336 &bytes_required));
337 if (bytes_required > modules_buffer_size) {
338 // Either there turned out to be more than 256 hmodules, or new hmodules
339 // could have loaded since the last try. Retry.
340 UnmapOrDie(hmodules, modules_buffer_size);
341 hmodules = 0;
342 modules_buffer_size = bytes_required;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700343 }
344 }
345
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700346 // |num_modules| is the number of modules actually present,
347 // |count| is the number of modules we return.
348 size_t nun_modules = bytes_required / sizeof(HMODULE),
349 count = 0;
350 for (size_t i = 0; i < nun_modules && count < max_modules; ++i) {
351 HMODULE handle = hmodules[i];
352 MODULEINFO mi;
353 if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi)))
354 continue;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700355
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700356 char module_name[MAX_PATH];
357 bool got_module_name =
358 GetModuleFileNameA(handle, module_name, sizeof(module_name));
359 if (!got_module_name)
360 module_name[0] = '\0';
361
362 if (filter && !filter(module_name))
363 continue;
364
365 uptr base_address = (uptr)mi.lpBaseOfDll;
366 uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage;
367 LoadedModule *cur_module = &modules[count];
368 cur_module->set(module_name, base_address);
369 // We add the whole module as one single address range.
370 cur_module->addAddressRange(base_address, end_address, /*executable*/ true);
371 count++;
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700372 }
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700373 UnmapOrDie(hmodules, modules_buffer_size);
374
375 return count;
376};
377
378#ifndef SANITIZER_GO
379// We can't use atexit() directly at __asan_init time as the CRT is not fully
380// initialized at this point. Place the functions into a vector and use
381// atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers).
382InternalMmapVectorNoCtor<void (*)(void)> atexit_functions;
383
384int Atexit(void (*function)(void)) {
385 atexit_functions.push_back(function);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700386 return 0;
Alexey Samsonova56aefd2012-06-05 08:32:53 +0000387}
388
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700389static int RunAtexit() {
390 int ret = 0;
391 for (uptr i = 0; i < atexit_functions.size(); ++i) {
392 ret |= atexit(atexit_functions[i]);
393 }
394 return ret;
395}
396
397#pragma section(".CRT$XID", long, read) // NOLINT
398static __declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit;
399#endif
400
401// ------------------ sanitizer_libc.h
402fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) {
403 if (mode != WrOnly)
404 UNIMPLEMENTED();
405 fd_t res = CreateFile(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
406 FILE_ATTRIBUTE_NORMAL, nullptr);
407 CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd);
408 CHECK(res != kStderrFd || kStderrFd == kInvalidFd);
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -0700409 if (res == kInvalidFd && last_error)
410 *last_error = GetLastError();
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700411 return res;
412}
413
414void CloseFile(fd_t fd) {
415 CloseHandle(fd);
416}
417
418bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
419 error_t *error_p) {
Alexey Samsonov4c9317a2013-02-04 10:16:50 +0000420 UNIMPLEMENTED();
421}
422
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700423bool SupportsColoredOutput(fd_t fd) {
424 // FIXME: support colored output.
425 return false;
Alexey Samsonov4c9317a2013-02-04 10:16:50 +0000426}
427
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700428bool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
429 error_t *error_p) {
430 CHECK(fd != kInvalidFd);
431
432 if (fd == kStdoutFd) {
433 fd = GetStdHandle(STD_OUTPUT_HANDLE);
434 if (fd == 0) fd = kInvalidFd;
435 } else if (fd == kStderrFd) {
436 fd = GetStdHandle(STD_ERROR_HANDLE);
437 if (fd == 0) fd = kInvalidFd;
438 }
439
440 DWORD internal_bytes_written;
441 if (fd == kInvalidFd ||
442 WriteFile(fd, buff, buff_size, &internal_bytes_written, 0)) {
443 if (error_p) *error_p = GetLastError();
444 return false;
445 } else {
446 if (bytes_written) *bytes_written = internal_bytes_written;
447 return true;
448 }
Alexey Samsonov4c9317a2013-02-04 10:16:50 +0000449}
450
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700451bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) {
Alexey Samsonovd1b8f582012-09-05 14:48:24 +0000452 UNIMPLEMENTED();
Alexey Samsonovd1b8f582012-09-05 14:48:24 +0000453}
454
Peter Collingbourne9578a3e2013-05-08 14:43:49 +0000455uptr internal_sched_yield() {
Dmitry Vyukov33b2a942012-11-06 13:19:59 +0000456 Sleep(0);
457 return 0;
Alexey Samsonov0969bcf2012-06-18 08:44:30 +0000458}
459
Alexey Samsonovf8822472013-02-20 13:54:32 +0000460void internal__exit(int exitcode) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700461 ExitProcess(exitcode);
Alexey Samsonovf8822472013-02-20 13:54:32 +0000462}
463
Stephen Hines6a211c52014-07-21 00:49:56 -0700464uptr internal_ftruncate(fd_t fd, uptr size) {
465 UNIMPLEMENTED();
466}
467
Stephen Hines86277eb2015-03-23 12:06:32 -0700468uptr GetRSS() {
469 return 0;
470}
471
472void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; }
473void internal_join_thread(void *th) { }
474
Dmitry Vyukovf4f51f22013-01-14 07:51:39 +0000475// ---------------------- BlockingMutex ---------------- {{{1
Dmitry Vyukovcf533b62013-02-04 10:42:38 +0000476const uptr LOCK_UNINITIALIZED = 0;
477const uptr LOCK_READY = (uptr)-1;
Dmitry Vyukovf4f51f22013-01-14 07:51:39 +0000478
479BlockingMutex::BlockingMutex(LinkerInitialized li) {
480 // FIXME: see comments in BlockingMutex::Lock() for the details.
481 CHECK(li == LINKER_INITIALIZED || owner_ == LOCK_UNINITIALIZED);
482
483 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
484 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
485 owner_ = LOCK_READY;
486}
487
Alexey Samsonov93af5942013-03-14 13:30:56 +0000488BlockingMutex::BlockingMutex() {
489 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
490 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
491 owner_ = LOCK_READY;
492}
493
Dmitry Vyukovf4f51f22013-01-14 07:51:39 +0000494void BlockingMutex::Lock() {
495 if (owner_ == LOCK_UNINITIALIZED) {
496 // FIXME: hm, global BlockingMutex objects are not initialized?!?
497 // This might be a side effect of the clang+cl+link Frankenbuild...
498 new(this) BlockingMutex((LinkerInitialized)(LINKER_INITIALIZED + 1));
499
500 // FIXME: If it turns out the linker doesn't invoke our
501 // constructors, we should probably manually Lock/Unlock all the global
502 // locks while we're starting in one thread to avoid double-init races.
503 }
504 EnterCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
Dmitry Vyukov8ceeec42013-02-04 08:07:45 +0000505 CHECK_EQ(owner_, LOCK_READY);
Dmitry Vyukovf4f51f22013-01-14 07:51:39 +0000506 owner_ = GetThreadSelf();
507}
508
509void BlockingMutex::Unlock() {
Dmitry Vyukov8ceeec42013-02-04 08:07:45 +0000510 CHECK_EQ(owner_, GetThreadSelf());
Dmitry Vyukovf4f51f22013-01-14 07:51:39 +0000511 owner_ = LOCK_READY;
512 LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
513}
514
Alexey Samsonovce700972013-03-11 15:45:20 +0000515void BlockingMutex::CheckLocked() {
516 CHECK_EQ(owner_, GetThreadSelf());
517}
518
Evgeniy Stepanovb114ed82013-03-13 08:19:53 +0000519uptr GetTlsSize() {
520 return 0;
521}
522
523void InitTlsSize() {
524}
525
Sergey Matveev24323de2013-05-07 14:41:43 +0000526void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
527 uptr *tls_addr, uptr *tls_size) {
Dmitry Vyukov21b3b1c2013-06-10 10:30:54 +0000528#ifdef SANITIZER_GO
529 *stk_addr = 0;
530 *stk_size = 0;
531 *tls_addr = 0;
532 *tls_size = 0;
533#else
Sergey Matveev24323de2013-05-07 14:41:43 +0000534 uptr stack_top, stack_bottom;
535 GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
536 *stk_addr = stack_bottom;
537 *stk_size = stack_top - stack_bottom;
538 *tls_addr = 0;
539 *tls_size = 0;
Dmitry Vyukov21b3b1c2013-06-10 10:30:54 +0000540#endif
Sergey Matveev24323de2013-05-07 14:41:43 +0000541}
542
Stephen Hines6d186232014-11-26 17:56:19 -0800543#if !SANITIZER_GO
Stephen Hines86277eb2015-03-23 12:06:32 -0700544void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) {
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700545 CHECK_GE(max_depth, 2);
Sergey Matveev736cf492013-05-08 12:45:55 +0000546 // FIXME: CaptureStackBackTrace might be too slow for us.
547 // FIXME: Compare with StackWalk64.
548 // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
Timur Iskhodzhanov7177d2b2013-11-09 13:59:12 +0000549 size = CaptureStackBackTrace(2, Min(max_depth, kStackTraceMax),
550 (void**)trace, 0);
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700551 if (size == 0)
552 return;
553
Sergey Matveev736cf492013-05-08 12:45:55 +0000554 // Skip the RTL frames by searching for the PC in the stacktrace.
Timur Iskhodzhanov7177d2b2013-11-09 13:59:12 +0000555 uptr pc_location = LocatePcInTrace(pc);
556 PopStackFrames(pc_location);
Sergey Matveev736cf492013-05-08 12:45:55 +0000557}
558
Stephen Hines6d186232014-11-26 17:56:19 -0800559void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
Stephen Hines86277eb2015-03-23 12:06:32 -0700560 u32 max_depth) {
Stephen Hines6d186232014-11-26 17:56:19 -0800561 CONTEXT ctx = *(CONTEXT *)context;
562 STACKFRAME64 stack_frame;
563 memset(&stack_frame, 0, sizeof(stack_frame));
564 size = 0;
565#if defined(_WIN64)
566 int machine_type = IMAGE_FILE_MACHINE_AMD64;
567 stack_frame.AddrPC.Offset = ctx.Rip;
568 stack_frame.AddrFrame.Offset = ctx.Rbp;
569 stack_frame.AddrStack.Offset = ctx.Rsp;
570#else
571 int machine_type = IMAGE_FILE_MACHINE_I386;
572 stack_frame.AddrPC.Offset = ctx.Eip;
573 stack_frame.AddrFrame.Offset = ctx.Ebp;
574 stack_frame.AddrStack.Offset = ctx.Esp;
575#endif
576 stack_frame.AddrPC.Mode = AddrModeFlat;
577 stack_frame.AddrFrame.Mode = AddrModeFlat;
578 stack_frame.AddrStack.Mode = AddrModeFlat;
579 while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(),
580 &stack_frame, &ctx, NULL, &SymFunctionTableAccess64,
581 &SymGetModuleBase64, NULL) &&
582 size < Min(max_depth, kStackTraceMax)) {
583 trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
584 }
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700585}
Stephen Hines6d186232014-11-26 17:56:19 -0800586#endif // #if !SANITIZER_GO
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700587
Stephen Hines86277eb2015-03-23 12:06:32 -0700588void ReportFile::Write(const char *buffer, uptr length) {
589 SpinMutexLock l(mu);
590 ReopenIfNecessary();
Pirama Arumuga Nainar259f7062015-05-06 11:49:53 -0700591 if (!WriteToFile(fd, buffer, length)) {
Reid Kleckner923bac72013-09-05 03:19:57 +0000592 // stderr may be closed, but we may be able to print to the debugger
593 // instead. This is the case when launching a program from Visual Studio,
594 // and the following routine should write to its console.
595 OutputDebugStringA(buffer);
596 }
597}
598
Stephen Hines2d1fdb22014-05-28 23:58:16 -0700599void SetAlternateSignalStack() {
600 // FIXME: Decide what to do on Windows.
601}
602
603void UnsetAlternateSignalStack() {
604 // FIXME: Decide what to do on Windows.
605}
606
607void InstallDeadlySignalHandlers(SignalHandlerType handler) {
608 (void)handler;
609 // FIXME: Decide what to do on Windows.
610}
611
612bool IsDeadlySignal(int signum) {
613 // FIXME: Decide what to do on Windows.
614 return false;
615}
616
Stephen Hines6d186232014-11-26 17:56:19 -0800617bool IsAccessibleMemoryRange(uptr beg, uptr size) {
618 // FIXME: Actually implement this function.
619 return true;
620}
621
Pirama Arumuga Nainar7c915052015-04-08 08:58:29 -0700622SignalContext SignalContext::Create(void *siginfo, void *context) {
623 EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD*)siginfo;
624 CONTEXT *context_record = (CONTEXT*)context;
625
626 uptr pc = (uptr)exception_record->ExceptionAddress;
627#ifdef _WIN64
628 uptr bp = (uptr)context_record->Rbp;
629 uptr sp = (uptr)context_record->Rsp;
630#else
631 uptr bp = (uptr)context_record->Ebp;
632 uptr sp = (uptr)context_record->Esp;
633#endif
634 uptr access_addr = exception_record->ExceptionInformation[1];
635
636 return SignalContext(context, access_addr, pc, sp, bp);
637}
638
Pirama Arumuga Nainarcdce50b2015-07-01 12:26:56 -0700639uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
640 // FIXME: Actually implement this function.
641 CHECK_GT(buf_len, 0);
642 buf[0] = 0;
643 return 0;
644}
645
Alexey Samsonovc5d46512012-06-05 07:05:10 +0000646} // namespace __sanitizer
647
648#endif // _WIN32