1353944Sdim//===-- sanitizer_win.cpp -------------------------------------------------===//
2353944Sdim//
3353944Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353944Sdim// See https://llvm.org/LICENSE.txt for license information.
5353944Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6353944Sdim//
7353944Sdim//===----------------------------------------------------------------------===//
8353944Sdim//
9353944Sdim// This file is shared between AddressSanitizer and ThreadSanitizer
10353944Sdim// run-time libraries and implements windows-specific functions from
11353944Sdim// sanitizer_libc.h.
12353944Sdim//===----------------------------------------------------------------------===//
13353944Sdim
14353944Sdim#include "sanitizer_platform.h"
15353944Sdim#if SANITIZER_WINDOWS
16353944Sdim
17353944Sdim#define WIN32_LEAN_AND_MEAN
18353944Sdim#define NOGDI
19353944Sdim#include <windows.h>
20353944Sdim#include <io.h>
21353944Sdim#include <psapi.h>
22353944Sdim#include <stdlib.h>
23353944Sdim
24353944Sdim#include "sanitizer_common.h"
25353944Sdim#include "sanitizer_file.h"
26353944Sdim#include "sanitizer_libc.h"
27353944Sdim#include "sanitizer_mutex.h"
28353944Sdim#include "sanitizer_placement_new.h"
29353944Sdim#include "sanitizer_win_defs.h"
30353944Sdim
31353944Sdim#if defined(PSAPI_VERSION) && PSAPI_VERSION == 1
32353944Sdim#pragma comment(lib, "psapi")
33353944Sdim#endif
34353944Sdim#if SANITIZER_WIN_TRACE
35353944Sdim#include <traceloggingprovider.h>
36353944Sdim//  Windows trace logging provider init
37353944Sdim#pragma comment(lib, "advapi32.lib")
38353944SdimTRACELOGGING_DECLARE_PROVIDER(g_asan_provider);
39353944Sdim// GUID must be the same in utils/AddressSanitizerLoggingProvider.wprp
40353944SdimTRACELOGGING_DEFINE_PROVIDER(g_asan_provider, "AddressSanitizerLoggingProvider",
41353944Sdim                             (0x6c6c766d, 0x3846, 0x4e6a, 0xa4, 0xfb, 0x5b,
42353944Sdim                              0x53, 0x0b, 0xd0, 0xf3, 0xfa));
43353944Sdim#else
44353944Sdim#define TraceLoggingUnregister(x)
45353944Sdim#endif
46353944Sdim
47353944Sdim// A macro to tell the compiler that this part of the code cannot be reached,
48353944Sdim// if the compiler supports this feature. Since we're using this in
49353944Sdim// code that is called when terminating the process, the expansion of the
50353944Sdim// macro should not terminate the process to avoid infinite recursion.
51353944Sdim#if defined(__clang__)
52353944Sdim# define BUILTIN_UNREACHABLE() __builtin_unreachable()
53353944Sdim#elif defined(__GNUC__) && \
54353944Sdim    (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
55353944Sdim# define BUILTIN_UNREACHABLE() __builtin_unreachable()
56353944Sdim#elif defined(_MSC_VER)
57353944Sdim# define BUILTIN_UNREACHABLE() __assume(0)
58353944Sdim#else
59353944Sdim# define BUILTIN_UNREACHABLE()
60353944Sdim#endif
61353944Sdim
62353944Sdimnamespace __sanitizer {
63353944Sdim
64353944Sdim#include "sanitizer_syscall_generic.inc"
65353944Sdim
66353944Sdim// --------------------- sanitizer_common.h
67353944Sdimuptr GetPageSize() {
68353944Sdim  SYSTEM_INFO si;
69353944Sdim  GetSystemInfo(&si);
70353944Sdim  return si.dwPageSize;
71353944Sdim}
72353944Sdim
73353944Sdimuptr GetMmapGranularity() {
74353944Sdim  SYSTEM_INFO si;
75353944Sdim  GetSystemInfo(&si);
76353944Sdim  return si.dwAllocationGranularity;
77353944Sdim}
78353944Sdim
79353944Sdimuptr GetMaxUserVirtualAddress() {
80353944Sdim  SYSTEM_INFO si;
81353944Sdim  GetSystemInfo(&si);
82353944Sdim  return (uptr)si.lpMaximumApplicationAddress;
83353944Sdim}
84353944Sdim
85353944Sdimuptr GetMaxVirtualAddress() {
86353944Sdim  return GetMaxUserVirtualAddress();
87353944Sdim}
88353944Sdim
89353944Sdimbool FileExists(const char *filename) {
90353944Sdim  return ::GetFileAttributesA(filename) != INVALID_FILE_ATTRIBUTES;
91353944Sdim}
92353944Sdim
93353944Sdimuptr internal_getpid() {
94353944Sdim  return GetProcessId(GetCurrentProcess());
95353944Sdim}
96353944Sdim
97353944Sdim// In contrast to POSIX, on Windows GetCurrentThreadId()
98353944Sdim// returns a system-unique identifier.
99353944Sdimtid_t GetTid() {
100353944Sdim  return GetCurrentThreadId();
101353944Sdim}
102353944Sdim
103353944Sdimuptr GetThreadSelf() {
104353944Sdim  return GetTid();
105353944Sdim}
106353944Sdim
107353944Sdim#if !SANITIZER_GO
108353944Sdimvoid GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
109353944Sdim                                uptr *stack_bottom) {
110353944Sdim  CHECK(stack_top);
111353944Sdim  CHECK(stack_bottom);
112353944Sdim  MEMORY_BASIC_INFORMATION mbi;
113353944Sdim  CHECK_NE(VirtualQuery(&mbi /* on stack */, &mbi, sizeof(mbi)), 0);
114353944Sdim  // FIXME: is it possible for the stack to not be a single allocation?
115353944Sdim  // Are these values what ASan expects to get (reserved, not committed;
116353944Sdim  // including stack guard page) ?
117353944Sdim  *stack_top = (uptr)mbi.BaseAddress + mbi.RegionSize;
118353944Sdim  *stack_bottom = (uptr)mbi.AllocationBase;
119353944Sdim}
120353944Sdim#endif  // #if !SANITIZER_GO
121353944Sdim
122353944Sdimvoid *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
123353944Sdim  void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
124353944Sdim  if (rv == 0)
125353944Sdim    ReportMmapFailureAndDie(size, mem_type, "allocate",
126353944Sdim                            GetLastError(), raw_report);
127353944Sdim  return rv;
128353944Sdim}
129353944Sdim
130353944Sdimvoid UnmapOrDie(void *addr, uptr size) {
131353944Sdim  if (!size || !addr)
132353944Sdim    return;
133353944Sdim
134353944Sdim  MEMORY_BASIC_INFORMATION mbi;
135353944Sdim  CHECK(VirtualQuery(addr, &mbi, sizeof(mbi)));
136353944Sdim
137353944Sdim  // MEM_RELEASE can only be used to unmap whole regions previously mapped with
138353944Sdim  // VirtualAlloc. So we first try MEM_RELEASE since it is better, and if that
139353944Sdim  // fails try MEM_DECOMMIT.
140353944Sdim  if (VirtualFree(addr, 0, MEM_RELEASE) == 0) {
141353944Sdim    if (VirtualFree(addr, size, MEM_DECOMMIT) == 0) {
142353944Sdim      Report("ERROR: %s failed to "
143353944Sdim             "deallocate 0x%zx (%zd) bytes at address %p (error code: %d)\n",
144353944Sdim             SanitizerToolName, size, size, addr, GetLastError());
145353944Sdim      CHECK("unable to unmap" && 0);
146353944Sdim    }
147353944Sdim  }
148353944Sdim}
149353944Sdim
150353944Sdimstatic void *ReturnNullptrOnOOMOrDie(uptr size, const char *mem_type,
151353944Sdim                                     const char *mmap_type) {
152353944Sdim  error_t last_error = GetLastError();
153353944Sdim  if (last_error == ERROR_NOT_ENOUGH_MEMORY)
154353944Sdim    return nullptr;
155353944Sdim  ReportMmapFailureAndDie(size, mem_type, mmap_type, last_error);
156353944Sdim}
157353944Sdim
158353944Sdimvoid *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
159353944Sdim  void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
160353944Sdim  if (rv == 0)
161353944Sdim    return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate");
162353944Sdim  return rv;
163353944Sdim}
164353944Sdim
165353944Sdim// We want to map a chunk of address space aligned to 'alignment'.
166353944Sdimvoid *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
167353944Sdim                                   const char *mem_type) {
168353944Sdim  CHECK(IsPowerOfTwo(size));
169353944Sdim  CHECK(IsPowerOfTwo(alignment));
170353944Sdim
171353944Sdim  // Windows will align our allocations to at least 64K.
172353944Sdim  alignment = Max(alignment, GetMmapGranularity());
173353944Sdim
174353944Sdim  uptr mapped_addr =
175353944Sdim      (uptr)VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
176353944Sdim  if (!mapped_addr)
177353944Sdim    return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned");
178353944Sdim
179353944Sdim  // If we got it right on the first try, return. Otherwise, unmap it and go to
180353944Sdim  // the slow path.
181353944Sdim  if (IsAligned(mapped_addr, alignment))
182353944Sdim    return (void*)mapped_addr;
183353944Sdim  if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0)
184353944Sdim    ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError());
185353944Sdim
186353944Sdim  // If we didn't get an aligned address, overallocate, find an aligned address,
187353944Sdim  // unmap, and try to allocate at that aligned address.
188353944Sdim  int retries = 0;
189353944Sdim  const int kMaxRetries = 10;
190353944Sdim  for (; retries < kMaxRetries &&
191353944Sdim         (mapped_addr == 0 || !IsAligned(mapped_addr, alignment));
192353944Sdim       retries++) {
193353944Sdim    // Overallocate size + alignment bytes.
194353944Sdim    mapped_addr =
195353944Sdim        (uptr)VirtualAlloc(0, size + alignment, MEM_RESERVE, PAGE_NOACCESS);
196353944Sdim    if (!mapped_addr)
197353944Sdim      return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned");
198353944Sdim
199353944Sdim    // Find the aligned address.
200353944Sdim    uptr aligned_addr = RoundUpTo(mapped_addr, alignment);
201353944Sdim
202353944Sdim    // Free the overallocation.
203353944Sdim    if (VirtualFree((void *)mapped_addr, 0, MEM_RELEASE) == 0)
204353944Sdim      ReportMmapFailureAndDie(size, mem_type, "deallocate", GetLastError());
205353944Sdim
206353944Sdim    // Attempt to allocate exactly the number of bytes we need at the aligned
207353944Sdim    // address. This may fail for a number of reasons, in which case we continue
208353944Sdim    // the loop.
209353944Sdim    mapped_addr = (uptr)VirtualAlloc((void *)aligned_addr, size,
210353944Sdim                                     MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
211353944Sdim  }
212353944Sdim
213353944Sdim  // Fail if we can't make this work quickly.
214353944Sdim  if (retries == kMaxRetries && mapped_addr == 0)
215353944Sdim    return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned");
216353944Sdim
217353944Sdim  return (void *)mapped_addr;
218353944Sdim}
219353944Sdim
220353944Sdimbool MmapFixedNoReserve(uptr fixed_addr, uptr size, const char *name) {
221353944Sdim  // FIXME: is this really "NoReserve"? On Win32 this does not matter much,
222353944Sdim  // but on Win64 it does.
223353944Sdim  (void)name;  // unsupported
224353944Sdim#if !SANITIZER_GO && SANITIZER_WINDOWS64
225353944Sdim  // On asan/Windows64, use MEM_COMMIT would result in error
226353944Sdim  // 1455:ERROR_COMMITMENT_LIMIT.
227353944Sdim  // Asan uses exception handler to commit page on demand.
228353944Sdim  void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE, PAGE_READWRITE);
229353944Sdim#else
230353944Sdim  void *p = VirtualAlloc((LPVOID)fixed_addr, size, MEM_RESERVE | MEM_COMMIT,
231353944Sdim                         PAGE_READWRITE);
232353944Sdim#endif
233353944Sdim  if (p == 0) {
234353944Sdim    Report("ERROR: %s failed to "
235353944Sdim           "allocate %p (%zd) bytes at %p (error code: %d)\n",
236353944Sdim           SanitizerToolName, size, size, fixed_addr, GetLastError());
237353944Sdim    return false;
238353944Sdim  }
239353944Sdim  return true;
240353944Sdim}
241353944Sdim
242353944Sdimbool MmapFixedSuperNoReserve(uptr fixed_addr, uptr size, const char *name) {
243353944Sdim  // FIXME: Windows support large pages too. Might be worth checking
244353944Sdim  return MmapFixedNoReserve(fixed_addr, size, name);
245353944Sdim}
246353944Sdim
247353944Sdim// Memory space mapped by 'MmapFixedOrDie' must have been reserved by
248353944Sdim// 'MmapFixedNoAccess'.
249353944Sdimvoid *MmapFixedOrDie(uptr fixed_addr, uptr size, const char *name) {
250353944Sdim  void *p = VirtualAlloc((LPVOID)fixed_addr, size,
251353944Sdim      MEM_COMMIT, PAGE_READWRITE);
252353944Sdim  if (p == 0) {
253353944Sdim    char mem_type[30];
254353944Sdim    internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
255353944Sdim                      fixed_addr);
256353944Sdim    ReportMmapFailureAndDie(size, mem_type, "allocate", GetLastError());
257353944Sdim  }
258353944Sdim  return p;
259353944Sdim}
260353944Sdim
261353944Sdim// Uses fixed_addr for now.
262353944Sdim// Will use offset instead once we've implemented this function for real.
263353944Sdimuptr ReservedAddressRange::Map(uptr fixed_addr, uptr size, const char *name) {
264353944Sdim  return reinterpret_cast<uptr>(MmapFixedOrDieOnFatalError(fixed_addr, size));
265353944Sdim}
266353944Sdim
267353944Sdimuptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr size,
268353944Sdim                                    const char *name) {
269353944Sdim  return reinterpret_cast<uptr>(MmapFixedOrDie(fixed_addr, size));
270353944Sdim}
271353944Sdim
272353944Sdimvoid ReservedAddressRange::Unmap(uptr addr, uptr size) {
273353944Sdim  // Only unmap if it covers the entire range.
274353944Sdim  CHECK((addr == reinterpret_cast<uptr>(base_)) && (size == size_));
275353944Sdim  // We unmap the whole range, just null out the base.
276353944Sdim  base_ = nullptr;
277353944Sdim  size_ = 0;
278353944Sdim  UnmapOrDie(reinterpret_cast<void*>(addr), size);
279353944Sdim}
280353944Sdim
281353944Sdimvoid *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size, const char *name) {
282353944Sdim  void *p = VirtualAlloc((LPVOID)fixed_addr, size,
283353944Sdim      MEM_COMMIT, PAGE_READWRITE);
284353944Sdim  if (p == 0) {
285353944Sdim    char mem_type[30];
286353944Sdim    internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
287353944Sdim                      fixed_addr);
288353944Sdim    return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate");
289353944Sdim  }
290353944Sdim  return p;
291353944Sdim}
292353944Sdim
293353944Sdimvoid *MmapNoReserveOrDie(uptr size, const char *mem_type) {
294353944Sdim  // FIXME: make this really NoReserve?
295353944Sdim  return MmapOrDie(size, mem_type);
296353944Sdim}
297353944Sdim
298353944Sdimuptr ReservedAddressRange::Init(uptr size, const char *name, uptr fixed_addr) {
299353944Sdim  base_ = fixed_addr ? MmapFixedNoAccess(fixed_addr, size) : MmapNoAccess(size);
300353944Sdim  size_ = size;
301353944Sdim  name_ = name;
302353944Sdim  (void)os_handle_;  // unsupported
303353944Sdim  return reinterpret_cast<uptr>(base_);
304353944Sdim}
305353944Sdim
306353944Sdim
307353944Sdimvoid *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {
308353944Sdim  (void)name; // unsupported
309353944Sdim  void *res = VirtualAlloc((LPVOID)fixed_addr, size,
310353944Sdim                           MEM_RESERVE, PAGE_NOACCESS);
311353944Sdim  if (res == 0)
312353944Sdim    Report("WARNING: %s failed to "
313353944Sdim           "mprotect %p (%zd) bytes at %p (error code: %d)\n",
314353944Sdim           SanitizerToolName, size, size, fixed_addr, GetLastError());
315353944Sdim  return res;
316353944Sdim}
317353944Sdim
318353944Sdimvoid *MmapNoAccess(uptr size) {
319353944Sdim  void *res = VirtualAlloc(nullptr, size, MEM_RESERVE, PAGE_NOACCESS);
320353944Sdim  if (res == 0)
321353944Sdim    Report("WARNING: %s failed to "
322353944Sdim           "mprotect %p (%zd) bytes (error code: %d)\n",
323353944Sdim           SanitizerToolName, size, size, GetLastError());
324353944Sdim  return res;
325353944Sdim}
326353944Sdim
327353944Sdimbool MprotectNoAccess(uptr addr, uptr size) {
328353944Sdim  DWORD old_protection;
329353944Sdim  return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection);
330353944Sdim}
331353944Sdim
332353944Sdimvoid ReleaseMemoryPagesToOS(uptr beg, uptr end) {
333353944Sdim  // This is almost useless on 32-bits.
334353944Sdim  // FIXME: add madvise-analog when we move to 64-bits.
335353944Sdim}
336353944Sdim
337353944Sdimvoid SetShadowRegionHugePageMode(uptr addr, uptr size) {
338353944Sdim  // FIXME: probably similar to ReleaseMemoryToOS.
339353944Sdim}
340353944Sdim
341353944Sdimbool DontDumpShadowMemory(uptr addr, uptr length) {
342353944Sdim  // This is almost useless on 32-bits.
343353944Sdim  // FIXME: add madvise-analog when we move to 64-bits.
344353944Sdim  return true;
345353944Sdim}
346353944Sdim
347353944Sdimuptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
348353944Sdim                              uptr *largest_gap_found,
349353944Sdim                              uptr *max_occupied_addr) {
350353944Sdim  uptr address = 0;
351353944Sdim  while (true) {
352353944Sdim    MEMORY_BASIC_INFORMATION info;
353353944Sdim    if (!::VirtualQuery((void*)address, &info, sizeof(info)))
354353944Sdim      return 0;
355353944Sdim
356353944Sdim    if (info.State == MEM_FREE) {
357353944Sdim      uptr shadow_address = RoundUpTo((uptr)info.BaseAddress + left_padding,
358353944Sdim                                      alignment);
359353944Sdim      if (shadow_address + size < (uptr)info.BaseAddress + info.RegionSize)
360353944Sdim        return shadow_address;
361353944Sdim    }
362353944Sdim
363353944Sdim    // Move to the next region.
364353944Sdim    address = (uptr)info.BaseAddress + info.RegionSize;
365353944Sdim  }
366353944Sdim  return 0;
367353944Sdim}
368353944Sdim
369353944Sdimbool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
370353944Sdim  MEMORY_BASIC_INFORMATION mbi;
371353944Sdim  CHECK(VirtualQuery((void *)range_start, &mbi, sizeof(mbi)));
372353944Sdim  return mbi.Protect == PAGE_NOACCESS &&
373353944Sdim         (uptr)mbi.BaseAddress + mbi.RegionSize >= range_end;
374353944Sdim}
375353944Sdim
376353944Sdimvoid *MapFileToMemory(const char *file_name, uptr *buff_size) {
377353944Sdim  UNIMPLEMENTED();
378353944Sdim}
379353944Sdim
380353944Sdimvoid *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset) {
381353944Sdim  UNIMPLEMENTED();
382353944Sdim}
383353944Sdim
384353944Sdimstatic const int kMaxEnvNameLength = 128;
385353944Sdimstatic const DWORD kMaxEnvValueLength = 32767;
386353944Sdim
387353944Sdimnamespace {
388353944Sdim
389353944Sdimstruct EnvVariable {
390353944Sdim  char name[kMaxEnvNameLength];
391353944Sdim  char value[kMaxEnvValueLength];
392353944Sdim};
393353944Sdim
394353944Sdim}  // namespace
395353944Sdim
396353944Sdimstatic const int kEnvVariables = 5;
397353944Sdimstatic EnvVariable env_vars[kEnvVariables];
398353944Sdimstatic int num_env_vars;
399353944Sdim
400353944Sdimconst char *GetEnv(const char *name) {
401353944Sdim  // Note: this implementation caches the values of the environment variables
402353944Sdim  // and limits their quantity.
403353944Sdim  for (int i = 0; i < num_env_vars; i++) {
404353944Sdim    if (0 == internal_strcmp(name, env_vars[i].name))
405353944Sdim      return env_vars[i].value;
406353944Sdim  }
407353944Sdim  CHECK_LT(num_env_vars, kEnvVariables);
408353944Sdim  DWORD rv = GetEnvironmentVariableA(name, env_vars[num_env_vars].value,
409353944Sdim                                     kMaxEnvValueLength);
410353944Sdim  if (rv > 0 && rv < kMaxEnvValueLength) {
411353944Sdim    CHECK_LT(internal_strlen(name), kMaxEnvNameLength);
412353944Sdim    internal_strncpy(env_vars[num_env_vars].name, name, kMaxEnvNameLength);
413353944Sdim    num_env_vars++;
414353944Sdim    return env_vars[num_env_vars - 1].value;
415353944Sdim  }
416353944Sdim  return 0;
417353944Sdim}
418353944Sdim
419353944Sdimconst char *GetPwd() {
420353944Sdim  UNIMPLEMENTED();
421353944Sdim}
422353944Sdim
423353944Sdimu32 GetUid() {
424353944Sdim  UNIMPLEMENTED();
425353944Sdim}
426353944Sdim
427353944Sdimnamespace {
428353944Sdimstruct ModuleInfo {
429353944Sdim  const char *filepath;
430353944Sdim  uptr base_address;
431353944Sdim  uptr end_address;
432353944Sdim};
433353944Sdim
434353944Sdim#if !SANITIZER_GO
435353944Sdimint CompareModulesBase(const void *pl, const void *pr) {
436353944Sdim  const ModuleInfo *l = (const ModuleInfo *)pl, *r = (const ModuleInfo *)pr;
437353944Sdim  if (l->base_address < r->base_address)
438353944Sdim    return -1;
439353944Sdim  return l->base_address > r->base_address;
440353944Sdim}
441353944Sdim#endif
442353944Sdim}  // namespace
443353944Sdim
444353944Sdim#if !SANITIZER_GO
445353944Sdimvoid DumpProcessMap() {
446353944Sdim  Report("Dumping process modules:\n");
447353944Sdim  ListOfModules modules;
448353944Sdim  modules.init();
449353944Sdim  uptr num_modules = modules.size();
450353944Sdim
451353944Sdim  InternalMmapVector<ModuleInfo> module_infos(num_modules);
452353944Sdim  for (size_t i = 0; i < num_modules; ++i) {
453353944Sdim    module_infos[i].filepath = modules[i].full_name();
454353944Sdim    module_infos[i].base_address = modules[i].ranges().front()->beg;
455353944Sdim    module_infos[i].end_address = modules[i].ranges().back()->end;
456353944Sdim  }
457353944Sdim  qsort(module_infos.data(), num_modules, sizeof(ModuleInfo),
458353944Sdim        CompareModulesBase);
459353944Sdim
460353944Sdim  for (size_t i = 0; i < num_modules; ++i) {
461353944Sdim    const ModuleInfo &mi = module_infos[i];
462353944Sdim    if (mi.end_address != 0) {
463353944Sdim      Printf("\t%p-%p %s\n", mi.base_address, mi.end_address,
464353944Sdim             mi.filepath[0] ? mi.filepath : "[no name]");
465353944Sdim    } else if (mi.filepath[0]) {
466353944Sdim      Printf("\t??\?-??? %s\n", mi.filepath);
467353944Sdim    } else {
468353944Sdim      Printf("\t???\n");
469353944Sdim    }
470353944Sdim  }
471353944Sdim}
472353944Sdim#endif
473353944Sdim
474353944Sdimvoid PrintModuleMap() { }
475353944Sdim
476353944Sdimvoid DisableCoreDumperIfNecessary() {
477353944Sdim  // Do nothing.
478353944Sdim}
479353944Sdim
480353944Sdimvoid ReExec() {
481353944Sdim  UNIMPLEMENTED();
482353944Sdim}
483353944Sdim
484353944Sdimvoid PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {}
485353944Sdim
486353944Sdimbool StackSizeIsUnlimited() {
487353944Sdim  UNIMPLEMENTED();
488353944Sdim}
489353944Sdim
490353944Sdimvoid SetStackSizeLimitInBytes(uptr limit) {
491353944Sdim  UNIMPLEMENTED();
492353944Sdim}
493353944Sdim
494353944Sdimbool AddressSpaceIsUnlimited() {
495353944Sdim  UNIMPLEMENTED();
496353944Sdim}
497353944Sdim
498353944Sdimvoid SetAddressSpaceUnlimited() {
499353944Sdim  UNIMPLEMENTED();
500353944Sdim}
501353944Sdim
502353944Sdimbool IsPathSeparator(const char c) {
503353944Sdim  return c == '\\' || c == '/';
504353944Sdim}
505353944Sdim
506353944Sdimstatic bool IsAlpha(char c) {
507353944Sdim  c = ToLower(c);
508353944Sdim  return c >= 'a' && c <= 'z';
509353944Sdim}
510353944Sdim
511353944Sdimbool IsAbsolutePath(const char *path) {
512353944Sdim  return path != nullptr && IsAlpha(path[0]) && path[1] == ':' &&
513353944Sdim         IsPathSeparator(path[2]);
514353944Sdim}
515353944Sdim
516353944Sdimvoid SleepForSeconds(int seconds) {
517353944Sdim  Sleep(seconds * 1000);
518353944Sdim}
519353944Sdim
520353944Sdimvoid SleepForMillis(int millis) {
521353944Sdim  Sleep(millis);
522353944Sdim}
523353944Sdim
524353944Sdimu64 NanoTime() {
525353944Sdim  static LARGE_INTEGER frequency = {};
526353944Sdim  LARGE_INTEGER counter;
527353944Sdim  if (UNLIKELY(frequency.QuadPart == 0)) {
528353944Sdim    QueryPerformanceFrequency(&frequency);
529353944Sdim    CHECK_NE(frequency.QuadPart, 0);
530353944Sdim  }
531353944Sdim  QueryPerformanceCounter(&counter);
532353944Sdim  counter.QuadPart *= 1000ULL * 1000000ULL;
533353944Sdim  counter.QuadPart /= frequency.QuadPart;
534353944Sdim  return counter.QuadPart;
535353944Sdim}
536353944Sdim
537353944Sdimu64 MonotonicNanoTime() { return NanoTime(); }
538353944Sdim
539353944Sdimvoid Abort() {
540353944Sdim  internal__exit(3);
541353944Sdim}
542353944Sdim
543353944Sdim#if !SANITIZER_GO
544353944Sdim// Read the file to extract the ImageBase field from the PE header. If ASLR is
545353944Sdim// disabled and this virtual address is available, the loader will typically
546353944Sdim// load the image at this address. Therefore, we call it the preferred base. Any
547353944Sdim// addresses in the DWARF typically assume that the object has been loaded at
548353944Sdim// this address.
549353944Sdimstatic uptr GetPreferredBase(const char *modname) {
550353944Sdim  fd_t fd = OpenFile(modname, RdOnly, nullptr);
551353944Sdim  if (fd == kInvalidFd)
552353944Sdim    return 0;
553353944Sdim  FileCloser closer(fd);
554353944Sdim
555353944Sdim  // Read just the DOS header.
556353944Sdim  IMAGE_DOS_HEADER dos_header;
557353944Sdim  uptr bytes_read;
558353944Sdim  if (!ReadFromFile(fd, &dos_header, sizeof(dos_header), &bytes_read) ||
559353944Sdim      bytes_read != sizeof(dos_header))
560353944Sdim    return 0;
561353944Sdim
562353944Sdim  // The file should start with the right signature.
563353944Sdim  if (dos_header.e_magic != IMAGE_DOS_SIGNATURE)
564353944Sdim    return 0;
565353944Sdim
566353944Sdim  // The layout at e_lfanew is:
567353944Sdim  // "PE\0\0"
568353944Sdim  // IMAGE_FILE_HEADER
569353944Sdim  // IMAGE_OPTIONAL_HEADER
570353944Sdim  // Seek to e_lfanew and read all that data.
571353944Sdim  char buf[4 + sizeof(IMAGE_FILE_HEADER) + sizeof(IMAGE_OPTIONAL_HEADER)];
572353944Sdim  if (::SetFilePointer(fd, dos_header.e_lfanew, nullptr, FILE_BEGIN) ==
573353944Sdim      INVALID_SET_FILE_POINTER)
574353944Sdim    return 0;
575353944Sdim  if (!ReadFromFile(fd, &buf[0], sizeof(buf), &bytes_read) ||
576353944Sdim      bytes_read != sizeof(buf))
577353944Sdim    return 0;
578353944Sdim
579353944Sdim  // Check for "PE\0\0" before the PE header.
580353944Sdim  char *pe_sig = &buf[0];
581353944Sdim  if (internal_memcmp(pe_sig, "PE\0\0", 4) != 0)
582353944Sdim    return 0;
583353944Sdim
584353944Sdim  // Skip over IMAGE_FILE_HEADER. We could do more validation here if we wanted.
585353944Sdim  IMAGE_OPTIONAL_HEADER *pe_header =
586353944Sdim      (IMAGE_OPTIONAL_HEADER *)(pe_sig + 4 + sizeof(IMAGE_FILE_HEADER));
587353944Sdim
588353944Sdim  // Check for more magic in the PE header.
589353944Sdim  if (pe_header->Magic != IMAGE_NT_OPTIONAL_HDR_MAGIC)
590353944Sdim    return 0;
591353944Sdim
592353944Sdim  // Finally, return the ImageBase.
593353944Sdim  return (uptr)pe_header->ImageBase;
594353944Sdim}
595353944Sdim
596353944Sdimvoid ListOfModules::init() {
597353944Sdim  clearOrInit();
598353944Sdim  HANDLE cur_process = GetCurrentProcess();
599353944Sdim
600353944Sdim  // Query the list of modules.  Start by assuming there are no more than 256
601353944Sdim  // modules and retry if that's not sufficient.
602353944Sdim  HMODULE *hmodules = 0;
603353944Sdim  uptr modules_buffer_size = sizeof(HMODULE) * 256;
604353944Sdim  DWORD bytes_required;
605353944Sdim  while (!hmodules) {
606353944Sdim    hmodules = (HMODULE *)MmapOrDie(modules_buffer_size, __FUNCTION__);
607353944Sdim    CHECK(EnumProcessModules(cur_process, hmodules, modules_buffer_size,
608353944Sdim                             &bytes_required));
609353944Sdim    if (bytes_required > modules_buffer_size) {
610353944Sdim      // Either there turned out to be more than 256 hmodules, or new hmodules
611353944Sdim      // could have loaded since the last try.  Retry.
612353944Sdim      UnmapOrDie(hmodules, modules_buffer_size);
613353944Sdim      hmodules = 0;
614353944Sdim      modules_buffer_size = bytes_required;
615353944Sdim    }
616353944Sdim  }
617353944Sdim
618353944Sdim  // |num_modules| is the number of modules actually present,
619353944Sdim  size_t num_modules = bytes_required / sizeof(HMODULE);
620353944Sdim  for (size_t i = 0; i < num_modules; ++i) {
621353944Sdim    HMODULE handle = hmodules[i];
622353944Sdim    MODULEINFO mi;
623353944Sdim    if (!GetModuleInformation(cur_process, handle, &mi, sizeof(mi)))
624353944Sdim      continue;
625353944Sdim
626353944Sdim    // Get the UTF-16 path and convert to UTF-8.
627353944Sdim    wchar_t modname_utf16[kMaxPathLength];
628353944Sdim    int modname_utf16_len =
629353944Sdim        GetModuleFileNameW(handle, modname_utf16, kMaxPathLength);
630353944Sdim    if (modname_utf16_len == 0)
631353944Sdim      modname_utf16[0] = '\0';
632353944Sdim    char module_name[kMaxPathLength];
633353944Sdim    int module_name_len =
634353944Sdim        ::WideCharToMultiByte(CP_UTF8, 0, modname_utf16, modname_utf16_len + 1,
635353944Sdim                              &module_name[0], kMaxPathLength, NULL, NULL);
636353944Sdim    module_name[module_name_len] = '\0';
637353944Sdim
638353944Sdim    uptr base_address = (uptr)mi.lpBaseOfDll;
639353944Sdim    uptr end_address = (uptr)mi.lpBaseOfDll + mi.SizeOfImage;
640353944Sdim
641353944Sdim    // Adjust the base address of the module so that we get a VA instead of an
642353944Sdim    // RVA when computing the module offset. This helps llvm-symbolizer find the
643353944Sdim    // right DWARF CU. In the common case that the image is loaded at it's
644353944Sdim    // preferred address, we will now print normal virtual addresses.
645353944Sdim    uptr preferred_base = GetPreferredBase(&module_name[0]);
646353944Sdim    uptr adjusted_base = base_address - preferred_base;
647353944Sdim
648353944Sdim    LoadedModule cur_module;
649353944Sdim    cur_module.set(module_name, adjusted_base);
650353944Sdim    // We add the whole module as one single address range.
651353944Sdim    cur_module.addAddressRange(base_address, end_address, /*executable*/ true,
652353944Sdim                               /*writable*/ true);
653353944Sdim    modules_.push_back(cur_module);
654353944Sdim  }
655353944Sdim  UnmapOrDie(hmodules, modules_buffer_size);
656353944Sdim}
657353944Sdim
658353944Sdimvoid ListOfModules::fallbackInit() { clear(); }
659353944Sdim
660353944Sdim// We can't use atexit() directly at __asan_init time as the CRT is not fully
661353944Sdim// initialized at this point.  Place the functions into a vector and use
662353944Sdim// atexit() as soon as it is ready for use (i.e. after .CRT$XIC initializers).
663353944SdimInternalMmapVectorNoCtor<void (*)(void)> atexit_functions;
664353944Sdim
665353944Sdimint Atexit(void (*function)(void)) {
666353944Sdim  atexit_functions.push_back(function);
667353944Sdim  return 0;
668353944Sdim}
669353944Sdim
670353944Sdimstatic int RunAtexit() {
671353944Sdim  TraceLoggingUnregister(g_asan_provider);
672353944Sdim  int ret = 0;
673353944Sdim  for (uptr i = 0; i < atexit_functions.size(); ++i) {
674353944Sdim    ret |= atexit(atexit_functions[i]);
675353944Sdim  }
676353944Sdim  return ret;
677353944Sdim}
678353944Sdim
679353944Sdim#pragma section(".CRT$XID", long, read)
680353944Sdim__declspec(allocate(".CRT$XID")) int (*__run_atexit)() = RunAtexit;
681353944Sdim#endif
682353944Sdim
683353944Sdim// ------------------ sanitizer_libc.h
684353944Sdimfd_t OpenFile(const char *filename, FileAccessMode mode, error_t *last_error) {
685353944Sdim  // FIXME: Use the wide variants to handle Unicode filenames.
686353944Sdim  fd_t res;
687353944Sdim  if (mode == RdOnly) {
688353944Sdim    res = CreateFileA(filename, GENERIC_READ,
689353944Sdim                      FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
690353944Sdim                      nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
691353944Sdim  } else if (mode == WrOnly) {
692353944Sdim    res = CreateFileA(filename, GENERIC_WRITE, 0, nullptr, CREATE_ALWAYS,
693353944Sdim                      FILE_ATTRIBUTE_NORMAL, nullptr);
694353944Sdim  } else {
695353944Sdim    UNIMPLEMENTED();
696353944Sdim  }
697353944Sdim  CHECK(res != kStdoutFd || kStdoutFd == kInvalidFd);
698353944Sdim  CHECK(res != kStderrFd || kStderrFd == kInvalidFd);
699353944Sdim  if (res == kInvalidFd && last_error)
700353944Sdim    *last_error = GetLastError();
701353944Sdim  return res;
702353944Sdim}
703353944Sdim
704353944Sdimvoid CloseFile(fd_t fd) {
705353944Sdim  CloseHandle(fd);
706353944Sdim}
707353944Sdim
708353944Sdimbool ReadFromFile(fd_t fd, void *buff, uptr buff_size, uptr *bytes_read,
709353944Sdim                  error_t *error_p) {
710353944Sdim  CHECK(fd != kInvalidFd);
711353944Sdim
712353944Sdim  // bytes_read can't be passed directly to ReadFile:
713353944Sdim  // uptr is unsigned long long on 64-bit Windows.
714353944Sdim  unsigned long num_read_long;
715353944Sdim
716353944Sdim  bool success = ::ReadFile(fd, buff, buff_size, &num_read_long, nullptr);
717353944Sdim  if (!success && error_p)
718353944Sdim    *error_p = GetLastError();
719353944Sdim  if (bytes_read)
720353944Sdim    *bytes_read = num_read_long;
721353944Sdim  return success;
722353944Sdim}
723353944Sdim
724353944Sdimbool SupportsColoredOutput(fd_t fd) {
725353944Sdim  // FIXME: support colored output.
726353944Sdim  return false;
727353944Sdim}
728353944Sdim
729353944Sdimbool WriteToFile(fd_t fd, const void *buff, uptr buff_size, uptr *bytes_written,
730353944Sdim                 error_t *error_p) {
731353944Sdim  CHECK(fd != kInvalidFd);
732353944Sdim
733353944Sdim  // Handle null optional parameters.
734353944Sdim  error_t dummy_error;
735353944Sdim  error_p = error_p ? error_p : &dummy_error;
736353944Sdim  uptr dummy_bytes_written;
737353944Sdim  bytes_written = bytes_written ? bytes_written : &dummy_bytes_written;
738353944Sdim
739353944Sdim  // Initialize output parameters in case we fail.
740353944Sdim  *error_p = 0;
741353944Sdim  *bytes_written = 0;
742353944Sdim
743353944Sdim  // Map the conventional Unix fds 1 and 2 to Windows handles. They might be
744353944Sdim  // closed, in which case this will fail.
745353944Sdim  if (fd == kStdoutFd || fd == kStderrFd) {
746353944Sdim    fd = GetStdHandle(fd == kStdoutFd ? STD_OUTPUT_HANDLE : STD_ERROR_HANDLE);
747353944Sdim    if (fd == 0) {
748353944Sdim      *error_p = ERROR_INVALID_HANDLE;
749353944Sdim      return false;
750353944Sdim    }
751353944Sdim  }
752353944Sdim
753353944Sdim  DWORD bytes_written_32;
754353944Sdim  if (!WriteFile(fd, buff, buff_size, &bytes_written_32, 0)) {
755353944Sdim    *error_p = GetLastError();
756353944Sdim    return false;
757353944Sdim  } else {
758353944Sdim    *bytes_written = bytes_written_32;
759353944Sdim    return true;
760353944Sdim  }
761353944Sdim}
762353944Sdim
763353944Sdimuptr internal_sched_yield() {
764353944Sdim  Sleep(0);
765353944Sdim  return 0;
766353944Sdim}
767353944Sdim
768353944Sdimvoid internal__exit(int exitcode) {
769353944Sdim  TraceLoggingUnregister(g_asan_provider);
770353944Sdim  // ExitProcess runs some finalizers, so use TerminateProcess to avoid that.
771353944Sdim  // The debugger doesn't stop on TerminateProcess like it does on ExitProcess,
772353944Sdim  // so add our own breakpoint here.
773353944Sdim  if (::IsDebuggerPresent())
774353944Sdim    __debugbreak();
775353944Sdim  TerminateProcess(GetCurrentProcess(), exitcode);
776353944Sdim  BUILTIN_UNREACHABLE();
777353944Sdim}
778353944Sdim
779353944Sdimuptr internal_ftruncate(fd_t fd, uptr size) {
780353944Sdim  UNIMPLEMENTED();
781353944Sdim}
782353944Sdim
783353944Sdimuptr GetRSS() {
784353944Sdim  PROCESS_MEMORY_COUNTERS counters;
785353944Sdim  if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters)))
786353944Sdim    return 0;
787353944Sdim  return counters.WorkingSetSize;
788353944Sdim}
789353944Sdim
790353944Sdimvoid *internal_start_thread(void (*func)(void *arg), void *arg) { return 0; }
791353944Sdimvoid internal_join_thread(void *th) { }
792353944Sdim
793353944Sdim// ---------------------- BlockingMutex ---------------- {{{1
794353944Sdim
795353944SdimBlockingMutex::BlockingMutex() {
796353944Sdim  CHECK(sizeof(SRWLOCK) <= sizeof(opaque_storage_));
797353944Sdim  internal_memset(this, 0, sizeof(*this));
798353944Sdim}
799353944Sdim
800353944Sdimvoid BlockingMutex::Lock() {
801353944Sdim  AcquireSRWLockExclusive((PSRWLOCK)opaque_storage_);
802353944Sdim  CHECK_EQ(owner_, 0);
803353944Sdim  owner_ = GetThreadSelf();
804353944Sdim}
805353944Sdim
806353944Sdimvoid BlockingMutex::Unlock() {
807353944Sdim  CheckLocked();
808353944Sdim  owner_ = 0;
809353944Sdim  ReleaseSRWLockExclusive((PSRWLOCK)opaque_storage_);
810353944Sdim}
811353944Sdim
812353944Sdimvoid BlockingMutex::CheckLocked() {
813353944Sdim  CHECK_EQ(owner_, GetThreadSelf());
814353944Sdim}
815353944Sdim
816353944Sdimuptr GetTlsSize() {
817353944Sdim  return 0;
818353944Sdim}
819353944Sdim
820353944Sdimvoid InitTlsSize() {
821353944Sdim}
822353944Sdim
823353944Sdimvoid GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
824353944Sdim                          uptr *tls_addr, uptr *tls_size) {
825353944Sdim#if SANITIZER_GO
826353944Sdim  *stk_addr = 0;
827353944Sdim  *stk_size = 0;
828353944Sdim  *tls_addr = 0;
829353944Sdim  *tls_size = 0;
830353944Sdim#else
831353944Sdim  uptr stack_top, stack_bottom;
832353944Sdim  GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
833353944Sdim  *stk_addr = stack_bottom;
834353944Sdim  *stk_size = stack_top - stack_bottom;
835353944Sdim  *tls_addr = 0;
836353944Sdim  *tls_size = 0;
837353944Sdim#endif
838353944Sdim}
839353944Sdim
840353944Sdimvoid ReportFile::Write(const char *buffer, uptr length) {
841353944Sdim  SpinMutexLock l(mu);
842353944Sdim  ReopenIfNecessary();
843353944Sdim  if (!WriteToFile(fd, buffer, length)) {
844353944Sdim    // stderr may be closed, but we may be able to print to the debugger
845353944Sdim    // instead.  This is the case when launching a program from Visual Studio,
846353944Sdim    // and the following routine should write to its console.
847353944Sdim    OutputDebugStringA(buffer);
848353944Sdim  }
849353944Sdim}
850353944Sdim
851353944Sdimvoid SetAlternateSignalStack() {
852353944Sdim  // FIXME: Decide what to do on Windows.
853353944Sdim}
854353944Sdim
855353944Sdimvoid UnsetAlternateSignalStack() {
856353944Sdim  // FIXME: Decide what to do on Windows.
857353944Sdim}
858353944Sdim
859353944Sdimvoid InstallDeadlySignalHandlers(SignalHandlerType handler) {
860353944Sdim  (void)handler;
861353944Sdim  // FIXME: Decide what to do on Windows.
862353944Sdim}
863353944Sdim
864353944SdimHandleSignalMode GetHandleSignalMode(int signum) {
865353944Sdim  // FIXME: Decide what to do on Windows.
866353944Sdim  return kHandleSignalNo;
867353944Sdim}
868353944Sdim
869353944Sdim// Check based on flags if we should handle this exception.
870353944Sdimbool IsHandledDeadlyException(DWORD exceptionCode) {
871353944Sdim  switch (exceptionCode) {
872353944Sdim    case EXCEPTION_ACCESS_VIOLATION:
873353944Sdim    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
874353944Sdim    case EXCEPTION_STACK_OVERFLOW:
875353944Sdim    case EXCEPTION_DATATYPE_MISALIGNMENT:
876353944Sdim    case EXCEPTION_IN_PAGE_ERROR:
877353944Sdim      return common_flags()->handle_segv;
878353944Sdim    case EXCEPTION_ILLEGAL_INSTRUCTION:
879353944Sdim    case EXCEPTION_PRIV_INSTRUCTION:
880353944Sdim    case EXCEPTION_BREAKPOINT:
881353944Sdim      return common_flags()->handle_sigill;
882353944Sdim    case EXCEPTION_FLT_DENORMAL_OPERAND:
883353944Sdim    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
884353944Sdim    case EXCEPTION_FLT_INEXACT_RESULT:
885353944Sdim    case EXCEPTION_FLT_INVALID_OPERATION:
886353944Sdim    case EXCEPTION_FLT_OVERFLOW:
887353944Sdim    case EXCEPTION_FLT_STACK_CHECK:
888353944Sdim    case EXCEPTION_FLT_UNDERFLOW:
889353944Sdim    case EXCEPTION_INT_DIVIDE_BY_ZERO:
890353944Sdim    case EXCEPTION_INT_OVERFLOW:
891353944Sdim      return common_flags()->handle_sigfpe;
892353944Sdim  }
893353944Sdim  return false;
894353944Sdim}
895353944Sdim
896353944Sdimbool IsAccessibleMemoryRange(uptr beg, uptr size) {
897353944Sdim  SYSTEM_INFO si;
898353944Sdim  GetNativeSystemInfo(&si);
899353944Sdim  uptr page_size = si.dwPageSize;
900353944Sdim  uptr page_mask = ~(page_size - 1);
901353944Sdim
902353944Sdim  for (uptr page = beg & page_mask, end = (beg + size - 1) & page_mask;
903353944Sdim       page <= end;) {
904353944Sdim    MEMORY_BASIC_INFORMATION info;
905353944Sdim    if (VirtualQuery((LPCVOID)page, &info, sizeof(info)) != sizeof(info))
906353944Sdim      return false;
907353944Sdim
908353944Sdim    if (info.Protect == 0 || info.Protect == PAGE_NOACCESS ||
909353944Sdim        info.Protect == PAGE_EXECUTE)
910353944Sdim      return false;
911353944Sdim
912353944Sdim    if (info.RegionSize == 0)
913353944Sdim      return false;
914353944Sdim
915353944Sdim    page += info.RegionSize;
916353944Sdim  }
917353944Sdim
918353944Sdim  return true;
919353944Sdim}
920353944Sdim
921353944Sdimbool SignalContext::IsStackOverflow() const {
922353944Sdim  return (DWORD)GetType() == EXCEPTION_STACK_OVERFLOW;
923353944Sdim}
924353944Sdim
925353944Sdimvoid SignalContext::InitPcSpBp() {
926353944Sdim  EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
927353944Sdim  CONTEXT *context_record = (CONTEXT *)context;
928353944Sdim
929353944Sdim  pc = (uptr)exception_record->ExceptionAddress;
930353944Sdim#ifdef _WIN64
931353944Sdim  bp = (uptr)context_record->Rbp;
932353944Sdim  sp = (uptr)context_record->Rsp;
933353944Sdim#else
934353944Sdim  bp = (uptr)context_record->Ebp;
935353944Sdim  sp = (uptr)context_record->Esp;
936353944Sdim#endif
937353944Sdim}
938353944Sdim
939353944Sdimuptr SignalContext::GetAddress() const {
940353944Sdim  EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
941353944Sdim  return exception_record->ExceptionInformation[1];
942353944Sdim}
943353944Sdim
944353944Sdimbool SignalContext::IsMemoryAccess() const {
945353944Sdim  return GetWriteFlag() != SignalContext::UNKNOWN;
946353944Sdim}
947353944Sdim
948353944Sdimbool SignalContext::IsTrueFaultingAddress() const {
949353944Sdim  // FIXME: Provide real implementation for this. See Linux and Mac variants.
950353944Sdim  return IsMemoryAccess();
951353944Sdim}
952353944Sdim
953353944SdimSignalContext::WriteFlag SignalContext::GetWriteFlag() const {
954353944Sdim  EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
955353944Sdim  // The contents of this array are documented at
956353944Sdim  // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx
957353944Sdim  // The first element indicates read as 0, write as 1, or execute as 8.  The
958353944Sdim  // second element is the faulting address.
959353944Sdim  switch (exception_record->ExceptionInformation[0]) {
960353944Sdim    case 0:
961353944Sdim      return SignalContext::READ;
962353944Sdim    case 1:
963353944Sdim      return SignalContext::WRITE;
964353944Sdim    case 8:
965353944Sdim      return SignalContext::UNKNOWN;
966353944Sdim  }
967353944Sdim  return SignalContext::UNKNOWN;
968353944Sdim}
969353944Sdim
970353944Sdimvoid SignalContext::DumpAllRegisters(void *context) {
971353944Sdim  // FIXME: Implement this.
972353944Sdim}
973353944Sdim
974353944Sdimint SignalContext::GetType() const {
975353944Sdim  return static_cast<const EXCEPTION_RECORD *>(siginfo)->ExceptionCode;
976353944Sdim}
977353944Sdim
978353944Sdimconst char *SignalContext::Describe() const {
979353944Sdim  unsigned code = GetType();
980353944Sdim  // Get the string description of the exception if this is a known deadly
981353944Sdim  // exception.
982353944Sdim  switch (code) {
983353944Sdim    case EXCEPTION_ACCESS_VIOLATION:
984353944Sdim      return "access-violation";
985353944Sdim    case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
986353944Sdim      return "array-bounds-exceeded";
987353944Sdim    case EXCEPTION_STACK_OVERFLOW:
988353944Sdim      return "stack-overflow";
989353944Sdim    case EXCEPTION_DATATYPE_MISALIGNMENT:
990353944Sdim      return "datatype-misalignment";
991353944Sdim    case EXCEPTION_IN_PAGE_ERROR:
992353944Sdim      return "in-page-error";
993353944Sdim    case EXCEPTION_ILLEGAL_INSTRUCTION:
994353944Sdim      return "illegal-instruction";
995353944Sdim    case EXCEPTION_PRIV_INSTRUCTION:
996353944Sdim      return "priv-instruction";
997353944Sdim    case EXCEPTION_BREAKPOINT:
998353944Sdim      return "breakpoint";
999353944Sdim    case EXCEPTION_FLT_DENORMAL_OPERAND:
1000353944Sdim      return "flt-denormal-operand";
1001353944Sdim    case EXCEPTION_FLT_DIVIDE_BY_ZERO:
1002353944Sdim      return "flt-divide-by-zero";
1003353944Sdim    case EXCEPTION_FLT_INEXACT_RESULT:
1004353944Sdim      return "flt-inexact-result";
1005353944Sdim    case EXCEPTION_FLT_INVALID_OPERATION:
1006353944Sdim      return "flt-invalid-operation";
1007353944Sdim    case EXCEPTION_FLT_OVERFLOW:
1008353944Sdim      return "flt-overflow";
1009353944Sdim    case EXCEPTION_FLT_STACK_CHECK:
1010353944Sdim      return "flt-stack-check";
1011353944Sdim    case EXCEPTION_FLT_UNDERFLOW:
1012353944Sdim      return "flt-underflow";
1013353944Sdim    case EXCEPTION_INT_DIVIDE_BY_ZERO:
1014353944Sdim      return "int-divide-by-zero";
1015353944Sdim    case EXCEPTION_INT_OVERFLOW:
1016353944Sdim      return "int-overflow";
1017353944Sdim  }
1018353944Sdim  return "unknown exception";
1019353944Sdim}
1020353944Sdim
1021353944Sdimuptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
1022353944Sdim  // FIXME: Actually implement this function.
1023353944Sdim  CHECK_GT(buf_len, 0);
1024353944Sdim  buf[0] = 0;
1025353944Sdim  return 0;
1026353944Sdim}
1027353944Sdim
1028353944Sdimuptr ReadLongProcessName(/*out*/char *buf, uptr buf_len) {
1029353944Sdim  return ReadBinaryName(buf, buf_len);
1030353944Sdim}
1031353944Sdim
1032353944Sdimvoid CheckVMASize() {
1033353944Sdim  // Do nothing.
1034353944Sdim}
1035353944Sdim
1036353944Sdimvoid InitializePlatformEarly() {
1037353944Sdim  // Do nothing.
1038353944Sdim}
1039353944Sdim
1040353944Sdimvoid MaybeReexec() {
1041353944Sdim  // No need to re-exec on Windows.
1042353944Sdim}
1043353944Sdim
1044353944Sdimvoid CheckASLR() {
1045353944Sdim  // Do nothing
1046353944Sdim}
1047353944Sdim
1048353944Sdimvoid CheckMPROTECT() {
1049353944Sdim  // Do nothing
1050353944Sdim}
1051353944Sdim
1052353944Sdimchar **GetArgv() {
1053353944Sdim  // FIXME: Actually implement this function.
1054353944Sdim  return 0;
1055353944Sdim}
1056353944Sdim
1057353944Sdimchar **GetEnviron() {
1058353944Sdim  // FIXME: Actually implement this function.
1059353944Sdim  return 0;
1060353944Sdim}
1061353944Sdim
1062353944Sdimpid_t StartSubprocess(const char *program, const char *const argv[],
1063353944Sdim                      fd_t stdin_fd, fd_t stdout_fd, fd_t stderr_fd) {
1064353944Sdim  // FIXME: implement on this platform
1065353944Sdim  // Should be implemented based on
1066353944Sdim  // SymbolizerProcess::StarAtSymbolizerSubprocess
1067353944Sdim  // from lib/sanitizer_common/sanitizer_symbolizer_win.cpp.
1068353944Sdim  return -1;
1069353944Sdim}
1070353944Sdim
1071353944Sdimbool IsProcessRunning(pid_t pid) {
1072353944Sdim  // FIXME: implement on this platform.
1073353944Sdim  return false;
1074353944Sdim}
1075353944Sdim
1076353944Sdimint WaitForProcess(pid_t pid) { return -1; }
1077353944Sdim
1078353944Sdim// FIXME implement on this platform.
1079353944Sdimvoid GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { }
1080353944Sdim
1081353944Sdimvoid CheckNoDeepBind(const char *filename, int flag) {
1082353944Sdim  // Do nothing.
1083353944Sdim}
1084353944Sdim
1085353944Sdim// FIXME: implement on this platform.
1086353944Sdimbool GetRandom(void *buffer, uptr length, bool blocking) {
1087353944Sdim  UNIMPLEMENTED();
1088353944Sdim}
1089353944Sdim
1090353944Sdimu32 GetNumberOfCPUs() {
1091353944Sdim  SYSTEM_INFO sysinfo = {};
1092353944Sdim  GetNativeSystemInfo(&sysinfo);
1093353944Sdim  return sysinfo.dwNumberOfProcessors;
1094353944Sdim}
1095353944Sdim
1096353944Sdim#if SANITIZER_WIN_TRACE
1097353944Sdim// TODO(mcgov): Rename this project-wide to PlatformLogInit
1098353944Sdimvoid AndroidLogInit(void) {
1099353944Sdim  HRESULT hr = TraceLoggingRegister(g_asan_provider);
1100353944Sdim  if (!SUCCEEDED(hr))
1101353944Sdim    return;
1102353944Sdim}
1103353944Sdim
1104353944Sdimvoid SetAbortMessage(const char *) {}
1105353944Sdim
1106353944Sdimvoid LogFullErrorReport(const char *buffer) {
1107353944Sdim  if (common_flags()->log_to_syslog) {
1108353944Sdim    InternalMmapVector<wchar_t> filename;
1109353944Sdim    DWORD filename_length = 0;
1110353944Sdim    do {
1111353944Sdim      filename.resize(filename.size() + 0x100);
1112353944Sdim      filename_length =
1113353944Sdim          GetModuleFileNameW(NULL, filename.begin(), filename.size());
1114353944Sdim    } while (filename_length >= filename.size());
1115353944Sdim    TraceLoggingWrite(g_asan_provider, "AsanReportEvent",
1116353944Sdim                      TraceLoggingValue(filename.begin(), "ExecutableName"),
1117353944Sdim                      TraceLoggingValue(buffer, "AsanReportContents"));
1118353944Sdim  }
1119353944Sdim}
1120353944Sdim#endif // SANITIZER_WIN_TRACE
1121353944Sdim
1122353944Sdim}  // namespace __sanitizer
1123353944Sdim
1124353944Sdim#endif  // _WIN32
1125