1 //===-- sanitizer_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 shared between AddressSanitizer and ThreadSanitizer
11 // run-time libraries and implements windows-specific functions from
12 // sanitizer_libc.h.
13 //===----------------------------------------------------------------------===//
14
15 #include "sanitizer_platform.h"
16 #if SANITIZER_WINDOWS
17
18 #define WIN32_LEAN_AND_MEAN
19 #define NOGDI
20 #include <windows.h>
21 #include <dbghelp.h>
22 #include <io.h>
23 #include <psapi.h>
24 #include <stdlib.h>
25
26 #include "sanitizer_common.h"
27 #include "sanitizer_libc.h"
28 #include "sanitizer_mutex.h"
29 #include "sanitizer_placement_new.h"
30 #include "sanitizer_stacktrace.h"
31
32 namespace __sanitizer {
33
34 #include "sanitizer_syscall_generic.inc"
35
36 // --------------------- sanitizer_common.h
GetPageSize()37 uptr GetPageSize() {
38 return 1U << 14; // FIXME: is this configurable?
39 }
40
GetMmapGranularity()41 uptr GetMmapGranularity() {
42 return 1U << 16; // FIXME: is this configurable?
43 }
44
GetMaxVirtualAddress()45 uptr GetMaxVirtualAddress() {
46 SYSTEM_INFO si;
47 GetSystemInfo(&si);
48 return (uptr)si.lpMaximumApplicationAddress;
49 }
50
FileExists(const char * filename)51 bool FileExists(const char *filename) {
52 UNIMPLEMENTED();
53 }
54
internal_getpid()55 uptr internal_getpid() {
56 return GetProcessId(GetCurrentProcess());
57 }
58
59 // In contrast to POSIX, on Windows GetCurrentThreadId()
60 // returns a system-unique identifier.
GetTid()61 uptr GetTid() {
62 return GetCurrentThreadId();
63 }
64
GetThreadSelf()65 uptr GetThreadSelf() {
66 return GetTid();
67 }
68
69 #if !SANITIZER_GO
GetThreadStackTopAndBottom(bool at_initialization,uptr * stack_top,uptr * stack_bottom)70 void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
71 uptr *stack_bottom) {
72 CHECK(stack_top);
73 CHECK(stack_bottom);
74 MEMORY_BASIC_INFORMATION mbi;
75 CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0);
76 // 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 }
82 #endif // #if !SANITIZER_GO
83
MmapOrDie(uptr size,const char * mem_type)84 void *MmapOrDie(uptr size, const char *mem_type) {
85 void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
86 if (rv == 0) {
87 Report("ERROR: %s failed to "
88 "allocate 0x%zx (%zd) bytes of %s (error code: %d)\n",
89 SanitizerToolName, size, size, mem_type, GetLastError());
90 CHECK("unable to mmap" && 0);
91 }
92 return rv;
93 }
94
UnmapOrDie(void * addr,uptr size)95 void UnmapOrDie(void *addr, uptr size) {
96 if (!size || !addr)
97 return;
98
99 if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
100 Report("ERROR: %s failed to "
101 "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n",
102 SanitizerToolName, size, size, addr, GetLastError());
103 CHECK("unable to unmap" && 0);
104 }
105 }
106
MmapFixedNoReserve(uptr fixed_addr,uptr size)107 void *MmapFixedNoReserve(uptr fixed_addr, uptr size) {
108 // FIXME: is this really "NoReserve"? On Win32 this does not matter much,
109 // but on Win64 it does.
110 void *p = VirtualAlloc((LPVOID)fixed_addr, size,
111 MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
112 if (p == 0)
113 Report("ERROR: %s failed to "
114 "allocate %p (%zd) bytes at %p (error code: %d)\n",
115 SanitizerToolName, size, size, fixed_addr, GetLastError());
116 return p;
117 }
118
MmapFixedOrDie(uptr fixed_addr,uptr size)119 void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
120 return MmapFixedNoReserve(fixed_addr, size);
121 }
122
MmapNoReserveOrDie(uptr size,const char * mem_type)123 void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
124 // FIXME: make this really NoReserve?
125 return MmapOrDie(size, mem_type);
126 }
127
MmapNoAccess(uptr fixed_addr,uptr size)128 void *MmapNoAccess(uptr fixed_addr, uptr size) {
129 void *res = VirtualAlloc((LPVOID)fixed_addr, size,
130 MEM_RESERVE | MEM_COMMIT, PAGE_NOACCESS);
131 if (res == 0)
132 Report("WARNING: %s failed to "
133 "mprotect %p (%zd) bytes at %p (error code: %d)\n",
134 SanitizerToolName, size, size, fixed_addr, GetLastError());
135 return res;
136 }
137
MprotectNoAccess(uptr addr,uptr size)138 bool MprotectNoAccess(uptr addr, uptr size) {
139 DWORD old_protection;
140 return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection);
141 }
142
143
FlushUnneededShadowMemory(uptr addr,uptr size)144 void FlushUnneededShadowMemory(uptr addr, uptr size) {
145 // This is almost useless on 32-bits.
146 // FIXME: add madvise-analog when we move to 64-bits.
147 }
148
NoHugePagesInRegion(uptr addr,uptr size)149 void NoHugePagesInRegion(uptr addr, uptr size) {
150 // FIXME: probably similar to FlushUnneededShadowMemory.
151 }
152
DontDumpShadowMemory(uptr addr,uptr length)153 void DontDumpShadowMemory(uptr addr, uptr length) {
154 // This is almost useless on 32-bits.
155 // FIXME: add madvise-analog when we move to 64-bits.
156 }
157
MemoryRangeIsAvailable(uptr range_start,uptr range_end)158 bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
159 MEMORY_BASIC_INFORMATION mbi;
160 CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi)));
161 return mbi.Protect == PAGE_NOACCESS &&
162 (uptr)mbi.BaseAddress + mbi.RegionSize >= range_end;
163 }
164
MapFileToMemory(const char * file_name,uptr * buff_size)165 void *MapFileToMemory(const char *file_name, uptr *buff_size) {
166 UNIMPLEMENTED();
167 }
168
MapWritableFileToMemory(void * addr,uptr size,fd_t fd,uptr offset)169 void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, uptr offset) {
170 UNIMPLEMENTED();
171 }
172
173 static const int kMaxEnvNameLength = 128;
174 static const DWORD kMaxEnvValueLength = 32767;
175
176 namespace {
177
178 struct EnvVariable {
179 char name[kMaxEnvNameLength];
180 char value[kMaxEnvValueLength];
181 };
182
183 } // namespace
184
185 static const int kEnvVariables = 5;
186 static EnvVariable env_vars[kEnvVariables];
187 static int num_env_vars;
188
GetEnv(const char * name)189 const char *GetEnv(const char *name) {
190 // Note: this implementation caches the values of the environment variables
191 // and limits their quantity.
192 for (int i = 0; i < num_env_vars; i++) {
193 if (0 == internal_strcmp(name, env_vars[i].name))
194 return env_vars[i].value;
195 }
196 CHECK_LT(num_env_vars, kEnvVariables);
197 DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value,
198 kMaxEnvValueLength);
199 if (rv > 0 && rv < kMaxEnvValueLength) {
200 CHECK_LT(internal_strlen(name), kMaxEnvNameLength);
201 internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength);
202 num_env_vars++;
203 return env_vars[num_env_vars - 1].value;
204 }
205 return 0;
206 }
207
GetPwd()208 const char *GetPwd() {
209 UNIMPLEMENTED();
210 }
211
GetUid()212 u32 GetUid() {
213 UNIMPLEMENTED();
214 }
215
216 namespace {
217 struct ModuleInfo {
218 const char *filepath;
219 uptr base_address;
220 uptr end_address;
221 };
222
CompareModulesBase(const void * pl,const void * pr)223 int CompareModulesBase(const void *pl, const void *pr) {
224 const ModuleInfo *l = (ModuleInfo *)pl, *r = (ModuleInfo *)pr;
225 if (l->base_address < r->base_address)
226 return -1;
227 return l->base_address > r->base_address;
228 }
229 } // namespace
230
231 #ifndef SANITIZER_GO
DumpProcessMap()232 void DumpProcessMap() {
233 Report("Dumping process modules:\n");
234 InternalScopedBuffer<LoadedModule> modules(kMaxNumberOfModules);
235 uptr num_modules =
236 GetListOfModules(modules.data(), kMaxNumberOfModules, nullptr);
237
238 InternalScopedBuffer<ModuleInfo> module_infos(num_modules);
239 for (size_t i = 0; i < num_modules; ++i) {
240 module_infos[i].filepath = modules[i].full_name();
241 module_infos[i].base_address = modules[i].base_address();
242 module_infos[i].end_address = modules[i].ranges().next()->end;
243 }
244 qsort(module_infos.data(), num_modules, sizeof(ModuleInfo),
245 CompareModulesBase);
246
247 for (size_t i = 0; i < num_modules; ++i) {
248 const ModuleInfo &mi = module_infos[i];
249 if (mi.end_address != 0) {
250 Printf("\t%p-%p %s\n", mi.base_address, mi.end_address,
251 mi.filepath[0] ? mi.filepath : "[no name]");
252 } else if (mi.filepath[0]) {
253 Printf("\t??\?-??? %s\n", mi.filepath);
254 } else {
255 Printf("\t???\n");
256 }
257 }
258 }
259 #endif
260
DisableCoreDumperIfNecessary()261 void DisableCoreDumperIfNecessary() {
262 // Do nothing.
263 }
264
ReExec()265 void ReExec() {
266 UNIMPLEMENTED();
267 }
268
PrepareForSandboxing(__sanitizer_sandbox_arguments * args)269 void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
270 (void)args;
271 // Nothing here for now.
272 }
273
StackSizeIsUnlimited()274 bool StackSizeIsUnlimited() {
275 UNIMPLEMENTED();
276 }
277
SetStackSizeLimitInBytes(uptr limit)278 void SetStackSizeLimitInBytes(uptr limit) {
279 UNIMPLEMENTED();
280 }
281
AddressSpaceIsUnlimited()282 bool AddressSpaceIsUnlimited() {
283 UNIMPLEMENTED();
284 }
285
SetAddressSpaceUnlimited()286 void SetAddressSpaceUnlimited() {
287 UNIMPLEMENTED();
288 }
289
FindPathToBinary(const char * name)290 char *FindPathToBinary(const char *name) {
291 // Nothing here for now.
292 return 0;
293 }
294
ReadBinaryName(char * buf,uptr buf_len)295 uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
296 // Nothing here for now.
297 return 0;
298 }
299
IsPathSeparator(const char c)300 bool IsPathSeparator(const char c) {
301 return c == '\\' || c == '/';
302 }
303
IsAbsolutePath(const char * path)304 bool IsAbsolutePath(const char *path) {
305 UNIMPLEMENTED();
306 }
307
SleepForSeconds(int seconds)308 void SleepForSeconds(int seconds) {
309 Sleep(seconds * 1000);
310 }
311
SleepForMillis(int millis)312 void SleepForMillis(int millis) {
313 Sleep(millis);
314 }
315
NanoTime()316 u64 NanoTime() {
317 return 0;
318 }
319
Abort()320 void Abort() {
321 if (::IsDebuggerPresent())
322 __debugbreak();
323 internal__exit(3);
324 }
325
GetListOfModules(LoadedModule * modules,uptr max_modules,string_predicate_t filter)326 uptr GetListOfModules(LoadedModule *modules, uptr max_modules,
327 string_predicate_t filter) {
328 HANDLE cur_process = GetCurrentProcess();
329
330 // Query the list of modules. Start by assuming there are no more than 256
331 // modules and retry if that's not sufficient.
332 HMODULE *hmodules = 0;
333 uptr modules_buffer_size = sizeof(HMODULE) * 256;
334 DWORD bytes_required;
335 while (!hmodules) {
336 hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__);
337 CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size,
338 &bytes_required));
339 if (bytes_required > modules_buffer_size) {
340 // Either there turned out to be more than 256 hmodules, or new hmodules
341 // could have loaded since the last try. Retry.
342 UnmapOrDie(hmodules, modules_buffer_size);
343 hmodules = 0;
344 modules_buffer_size = bytes_required;
345 }
346 }
347
348 // |num_modules| is the number of modules actually present,
349 // |count| is the number of modules we return.
350 size_t nun_modules = bytes_required / sizeof(HMODULE),
351 count = 0;
352 for (size_t i = 0; i < nun_modules && count < max_modules; ++i) {
353 HMODULE handle = hmodules[i];
354 MODULEINFO mi;
355 if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi)))
356 continue;
357
358 char module_name[MAX_PATH];
359 bool got_module_name =
360 GetModuleFileNameA(handle, module_name, sizeof(module_name));
361 if (!got_module_name)
362 module_name[0] = '\0';
363
364 if (filter && !filter(module_name))
365 continue;
366
367 uptr base_address = (uptr)mi.lpBaseOfDll;
368 uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage;
369 LoadedModule *cur_module = &modules[count];
370 cur_module->set(module_name, base_address);
371 // We add the whole module as one single address range.
372 cur_module->addAddressRange(base_address, end_address, /*executable*/ true);
373 count++;
374 }
375 UnmapOrDie(hmodules, modules_buffer_size);
376
377 return count;
378 };
379
380 #ifndef SANITIZER_GO
381 // We can't use atexit() directly at __asan_init time as the CRT is not fully
382 // initialized at this point. Place the functions into a vector and use
383 // atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers).
384 InternalMmapVectorNoCtor<void (*)(void)> atexit_functions;
385
Atexit(void (* function)(void))386 int Atexit(void (*function)(void)) {
387 atexit_functions.push_back(function);
388 return 0;
389 }
390
RunAtexit()391 static int RunAtexit() {
392 int ret = 0;
393 for (uptr i = 0; i < atexit_functions.size(); ++i) {
394 ret |= atexit(atexit_functions[i]);
395 }
396 return ret;
397 }
398
399 #pragma section(".CRT$XID", long, read) // NOLINT
400 static __declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit;
401 #endif
402
403 // ------------------ sanitizer_libc.h
OpenFile(const char * filename,FileAccessMode mode,error_t * last_error)404 fd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) {
405 if (mode != WrOnly)
406 UNIMPLEMENTED();
407 fd_t res = CreateFile(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
408 FILE_ATTRIBUTE_NORMAL, nullptr);
409 CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd);
410 CHECK(res != kStderrFd || kStderrFd == kInvalidFd);
411 return res;
412 }
413
CloseFile(fd_t fd)414 void CloseFile(fd_t fd) {
415 CloseHandle(fd);
416 }
417
ReadFromFile(fd_t fd,void * buff,uptr buff_size,uptr * bytes_read,error_t * error_p)418 bool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
419 error_t *error_p) {
420 UNIMPLEMENTED();
421 }
422
SupportsColoredOutput(fd_t fd)423 bool SupportsColoredOutput(fd_t fd) {
424 // FIXME: support colored output.
425 return false;
426 }
427
WriteToFile(fd_t fd,const void * buff,uptr buff_size,uptr * bytes_written,error_t * error_p)428 bool 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 }
449 }
450
RenameFile(const char * oldpath,const char * newpath,error_t * error_p)451 bool RenameFile(const char *oldpath, const char *newpath, error_t *error_p) {
452 UNIMPLEMENTED();
453 }
454
internal_sched_yield()455 uptr internal_sched_yield() {
456 Sleep(0);
457 return 0;
458 }
459
internal__exit(int exitcode)460 void internal__exit(int exitcode) {
461 ExitProcess(exitcode);
462 }
463
internal_ftruncate(fd_t fd,uptr size)464 uptr internal_ftruncate(fd_t fd, uptr size) {
465 UNIMPLEMENTED();
466 }
467
GetRSS()468 uptr GetRSS() {
469 return 0;
470 }
471
internal_start_thread(void (* func)(void * arg),void * arg)472 void *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; }
internal_join_thread(void * th)473 void internal_join_thread(void *th) { }
474
475 // ---------------------- BlockingMutex ---------------- {{{1
476 const uptr LOCK_UNINITIALIZED = 0;
477 const uptr LOCK_READY = (uptr)-1;
478
BlockingMutex(LinkerInitialized li)479 BlockingMutex::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
BlockingMutex()488 BlockingMutex::BlockingMutex() {
489 CHECK(sizeof(CRITICAL_SECTION) <= sizeof(opaque_storage_));
490 InitializeCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
491 owner_ = LOCK_READY;
492 }
493
Lock()494 void 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_);
505 CHECK_EQ(owner_, LOCK_READY);
506 owner_ = GetThreadSelf();
507 }
508
Unlock()509 void BlockingMutex::Unlock() {
510 CHECK_EQ(owner_, GetThreadSelf());
511 owner_ = LOCK_READY;
512 LeaveCriticalSection((LPCRITICAL_SECTION)opaque_storage_);
513 }
514
CheckLocked()515 void BlockingMutex::CheckLocked() {
516 CHECK_EQ(owner_, GetThreadSelf());
517 }
518
GetTlsSize()519 uptr GetTlsSize() {
520 return 0;
521 }
522
InitTlsSize()523 void InitTlsSize() {
524 }
525
GetThreadStackAndTls(bool main,uptr * stk_addr,uptr * stk_size,uptr * tls_addr,uptr * tls_size)526 void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
527 uptr *tls_addr, uptr *tls_size) {
528 #ifdef SANITIZER_GO
529 *stk_addr = 0;
530 *stk_size = 0;
531 *tls_addr = 0;
532 *tls_size = 0;
533 #else
534 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;
540 #endif
541 }
542
543 #if !SANITIZER_GO
SlowUnwindStack(uptr pc,u32 max_depth)544 void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) {
545 CHECK_GE(max_depth, 2);
546 // FIXME: CaptureStackBackTrace might be too slow for us.
547 // FIXME: Compare with StackWalk64.
548 // FIXME: Look at LLVMUnhandledExceptionFilter in Signals.inc
549 size = CaptureStackBackTrace(2, Min(max_depth, kStackTraceMax),
550 (void**)trace, 0);
551 if (size == 0)
552 return;
553
554 // Skip the RTL frames by searching for the PC in the stacktrace.
555 uptr pc_location = LocatePcInTrace(pc);
556 PopStackFrames(pc_location);
557 }
558
SlowUnwindStackWithContext(uptr pc,void * context,u32 max_depth)559 void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
560 u32 max_depth) {
561 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 }
585 }
586 #endif // #if !SANITIZER_GO
587
Write(const char * buffer,uptr length)588 void ReportFile::Write(const char *buffer, uptr length) {
589 SpinMutexLock l(mu);
590 ReopenIfNecessary();
591 if (!WriteToFile(fd, buffer, length)) {
592 // 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
SetAlternateSignalStack()599 void SetAlternateSignalStack() {
600 // FIXME: Decide what to do on Windows.
601 }
602
UnsetAlternateSignalStack()603 void UnsetAlternateSignalStack() {
604 // FIXME: Decide what to do on Windows.
605 }
606
InstallDeadlySignalHandlers(SignalHandlerType handler)607 void InstallDeadlySignalHandlers(SignalHandlerType handler) {
608 (void)handler;
609 // FIXME: Decide what to do on Windows.
610 }
611
IsDeadlySignal(int signum)612 bool IsDeadlySignal(int signum) {
613 // FIXME: Decide what to do on Windows.
614 return false;
615 }
616
IsAccessibleMemoryRange(uptr beg,uptr size)617 bool IsAccessibleMemoryRange(uptr beg, uptr size) {
618 // FIXME: Actually implement this function.
619 return true;
620 }
621
Create(void * siginfo,void * context)622 SignalContext 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
639 } // namespace __sanitizer
640
641 #endif // _WIN32
642