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