xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp (revision 5ffd83dbcc34f10e07f6d3e968ae6365869615f4)
168d75effSDimitry Andric //===-- sanitizer_fuchsia.cpp ---------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is shared between AddressSanitizer and other sanitizer
1068d75effSDimitry Andric // run-time libraries and implements Fuchsia-specific functions from
1168d75effSDimitry Andric // sanitizer_common.h.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric 
1468d75effSDimitry Andric #include "sanitizer_fuchsia.h"
1568d75effSDimitry Andric #if SANITIZER_FUCHSIA
1668d75effSDimitry Andric 
1768d75effSDimitry Andric #include "sanitizer_common.h"
1868d75effSDimitry Andric #include "sanitizer_libc.h"
1968d75effSDimitry Andric #include "sanitizer_mutex.h"
2068d75effSDimitry Andric 
2168d75effSDimitry Andric #include <limits.h>
2268d75effSDimitry Andric #include <pthread.h>
2368d75effSDimitry Andric #include <stdlib.h>
2468d75effSDimitry Andric #include <unistd.h>
2568d75effSDimitry Andric #include <zircon/errors.h>
2668d75effSDimitry Andric #include <zircon/process.h>
2768d75effSDimitry Andric #include <zircon/syscalls.h>
2868d75effSDimitry Andric 
2968d75effSDimitry Andric namespace __sanitizer {
3068d75effSDimitry Andric 
3168d75effSDimitry Andric void NORETURN internal__exit(int exitcode) { _zx_process_exit(exitcode); }
3268d75effSDimitry Andric 
3368d75effSDimitry Andric uptr internal_sched_yield() {
3468d75effSDimitry Andric   zx_status_t status = _zx_nanosleep(0);
3568d75effSDimitry Andric   CHECK_EQ(status, ZX_OK);
3668d75effSDimitry Andric   return 0;  // Why doesn't this return void?
3768d75effSDimitry Andric }
3868d75effSDimitry Andric 
3968d75effSDimitry Andric static void internal_nanosleep(zx_time_t ns) {
4068d75effSDimitry Andric   zx_status_t status = _zx_nanosleep(_zx_deadline_after(ns));
4168d75effSDimitry Andric   CHECK_EQ(status, ZX_OK);
4268d75effSDimitry Andric }
4368d75effSDimitry Andric 
4468d75effSDimitry Andric unsigned int internal_sleep(unsigned int seconds) {
4568d75effSDimitry Andric   internal_nanosleep(ZX_SEC(seconds));
4668d75effSDimitry Andric   return 0;
4768d75effSDimitry Andric }
4868d75effSDimitry Andric 
4968d75effSDimitry Andric u64 NanoTime() {
5068d75effSDimitry Andric   zx_time_t time;
5168d75effSDimitry Andric   zx_status_t status = _zx_clock_get(ZX_CLOCK_UTC, &time);
5268d75effSDimitry Andric   CHECK_EQ(status, ZX_OK);
5368d75effSDimitry Andric   return time;
5468d75effSDimitry Andric }
5568d75effSDimitry Andric 
5668d75effSDimitry Andric u64 MonotonicNanoTime() { return _zx_clock_get_monotonic(); }
5768d75effSDimitry Andric 
5868d75effSDimitry Andric uptr internal_getpid() {
5968d75effSDimitry Andric   zx_info_handle_basic_t info;
6068d75effSDimitry Andric   zx_status_t status =
6168d75effSDimitry Andric       _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &info,
6268d75effSDimitry Andric                           sizeof(info), NULL, NULL);
6368d75effSDimitry Andric   CHECK_EQ(status, ZX_OK);
6468d75effSDimitry Andric   uptr pid = static_cast<uptr>(info.koid);
6568d75effSDimitry Andric   CHECK_EQ(pid, info.koid);
6668d75effSDimitry Andric   return pid;
6768d75effSDimitry Andric }
6868d75effSDimitry Andric 
69*5ffd83dbSDimitry Andric int internal_dlinfo(void *handle, int request, void *p) {
70*5ffd83dbSDimitry Andric   UNIMPLEMENTED();
71*5ffd83dbSDimitry Andric }
72*5ffd83dbSDimitry Andric 
7368d75effSDimitry Andric uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); }
7468d75effSDimitry Andric 
7568d75effSDimitry Andric tid_t GetTid() { return GetThreadSelf(); }
7668d75effSDimitry Andric 
7768d75effSDimitry Andric void Abort() { abort(); }
7868d75effSDimitry Andric 
7968d75effSDimitry Andric int Atexit(void (*function)(void)) { return atexit(function); }
8068d75effSDimitry Andric 
8168d75effSDimitry Andric void SleepForSeconds(int seconds) { internal_sleep(seconds); }
8268d75effSDimitry Andric 
8368d75effSDimitry Andric void SleepForMillis(int millis) { internal_nanosleep(ZX_MSEC(millis)); }
8468d75effSDimitry Andric 
8568d75effSDimitry Andric void GetThreadStackTopAndBottom(bool, uptr *stack_top, uptr *stack_bottom) {
8668d75effSDimitry Andric   pthread_attr_t attr;
8768d75effSDimitry Andric   CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
8868d75effSDimitry Andric   void *base;
8968d75effSDimitry Andric   size_t size;
9068d75effSDimitry Andric   CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0);
9168d75effSDimitry Andric   CHECK_EQ(pthread_attr_destroy(&attr), 0);
9268d75effSDimitry Andric 
9368d75effSDimitry Andric   *stack_bottom = reinterpret_cast<uptr>(base);
9468d75effSDimitry Andric   *stack_top = *stack_bottom + size;
9568d75effSDimitry Andric }
9668d75effSDimitry Andric 
9768d75effSDimitry Andric void InitializePlatformEarly() {}
9868d75effSDimitry Andric void MaybeReexec() {}
9968d75effSDimitry Andric void CheckASLR() {}
10068d75effSDimitry Andric void CheckMPROTECT() {}
10168d75effSDimitry Andric void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {}
10268d75effSDimitry Andric void DisableCoreDumperIfNecessary() {}
10368d75effSDimitry Andric void InstallDeadlySignalHandlers(SignalHandlerType handler) {}
10468d75effSDimitry Andric void SetAlternateSignalStack() {}
10568d75effSDimitry Andric void UnsetAlternateSignalStack() {}
10668d75effSDimitry Andric void InitTlsSize() {}
10768d75effSDimitry Andric 
10868d75effSDimitry Andric void PrintModuleMap() {}
10968d75effSDimitry Andric 
11068d75effSDimitry Andric bool SignalContext::IsStackOverflow() const { return false; }
11168d75effSDimitry Andric void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); }
11268d75effSDimitry Andric const char *SignalContext::Describe() const { UNIMPLEMENTED(); }
11368d75effSDimitry Andric 
11468d75effSDimitry Andric enum MutexState : int { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 };
11568d75effSDimitry Andric 
11668d75effSDimitry Andric BlockingMutex::BlockingMutex() {
11768d75effSDimitry Andric   // NOTE!  It's important that this use internal_memset, because plain
11868d75effSDimitry Andric   // memset might be intercepted (e.g., actually be __asan_memset).
11968d75effSDimitry Andric   // Defining this so the compiler initializes each field, e.g.:
12068d75effSDimitry Andric   //   BlockingMutex::BlockingMutex() : BlockingMutex(LINKER_INITIALIZED) {}
12168d75effSDimitry Andric   // might result in the compiler generating a call to memset, which would
12268d75effSDimitry Andric   // have the same problem.
12368d75effSDimitry Andric   internal_memset(this, 0, sizeof(*this));
12468d75effSDimitry Andric }
12568d75effSDimitry Andric 
12668d75effSDimitry Andric void BlockingMutex::Lock() {
12768d75effSDimitry Andric   CHECK_EQ(owner_, 0);
12868d75effSDimitry Andric   atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
12968d75effSDimitry Andric   if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
13068d75effSDimitry Andric     return;
13168d75effSDimitry Andric   while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) {
13268d75effSDimitry Andric     zx_status_t status =
13368d75effSDimitry Andric         _zx_futex_wait(reinterpret_cast<zx_futex_t *>(m), MtxSleeping,
13468d75effSDimitry Andric                        ZX_HANDLE_INVALID, ZX_TIME_INFINITE);
13568d75effSDimitry Andric     if (status != ZX_ERR_BAD_STATE)  // Normal race.
13668d75effSDimitry Andric       CHECK_EQ(status, ZX_OK);
13768d75effSDimitry Andric   }
13868d75effSDimitry Andric }
13968d75effSDimitry Andric 
14068d75effSDimitry Andric void BlockingMutex::Unlock() {
14168d75effSDimitry Andric   atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
14268d75effSDimitry Andric   u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release);
14368d75effSDimitry Andric   CHECK_NE(v, MtxUnlocked);
14468d75effSDimitry Andric   if (v == MtxSleeping) {
14568d75effSDimitry Andric     zx_status_t status = _zx_futex_wake(reinterpret_cast<zx_futex_t *>(m), 1);
14668d75effSDimitry Andric     CHECK_EQ(status, ZX_OK);
14768d75effSDimitry Andric   }
14868d75effSDimitry Andric }
14968d75effSDimitry Andric 
15068d75effSDimitry Andric void BlockingMutex::CheckLocked() {
15168d75effSDimitry Andric   atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
15268d75effSDimitry Andric   CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
15368d75effSDimitry Andric }
15468d75effSDimitry Andric 
15568d75effSDimitry Andric uptr GetPageSize() { return PAGE_SIZE; }
15668d75effSDimitry Andric 
15768d75effSDimitry Andric uptr GetMmapGranularity() { return PAGE_SIZE; }
15868d75effSDimitry Andric 
15968d75effSDimitry Andric sanitizer_shadow_bounds_t ShadowBounds;
16068d75effSDimitry Andric 
16168d75effSDimitry Andric uptr GetMaxUserVirtualAddress() {
16268d75effSDimitry Andric   ShadowBounds = __sanitizer_shadow_bounds();
16368d75effSDimitry Andric   return ShadowBounds.memory_limit - 1;
16468d75effSDimitry Andric }
16568d75effSDimitry Andric 
16668d75effSDimitry Andric uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); }
16768d75effSDimitry Andric 
16868d75effSDimitry Andric static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type,
16968d75effSDimitry Andric                                   bool raw_report, bool die_for_nomem) {
17068d75effSDimitry Andric   size = RoundUpTo(size, PAGE_SIZE);
17168d75effSDimitry Andric 
17268d75effSDimitry Andric   zx_handle_t vmo;
17368d75effSDimitry Andric   zx_status_t status = _zx_vmo_create(size, 0, &vmo);
17468d75effSDimitry Andric   if (status != ZX_OK) {
17568d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY || die_for_nomem)
17668d75effSDimitry Andric       ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status,
17768d75effSDimitry Andric                               raw_report);
17868d75effSDimitry Andric     return nullptr;
17968d75effSDimitry Andric   }
18068d75effSDimitry Andric   _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type,
18168d75effSDimitry Andric                           internal_strlen(mem_type));
18268d75effSDimitry Andric 
18368d75effSDimitry Andric   // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that?
18468d75effSDimitry Andric   uintptr_t addr;
18568d75effSDimitry Andric   status =
18668d75effSDimitry Andric       _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0,
18768d75effSDimitry Andric                    vmo, 0, size, &addr);
18868d75effSDimitry Andric   _zx_handle_close(vmo);
18968d75effSDimitry Andric 
19068d75effSDimitry Andric   if (status != ZX_OK) {
19168d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY || die_for_nomem)
19268d75effSDimitry Andric       ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status,
19368d75effSDimitry Andric                               raw_report);
19468d75effSDimitry Andric     return nullptr;
19568d75effSDimitry Andric   }
19668d75effSDimitry Andric 
19768d75effSDimitry Andric   IncreaseTotalMmap(size);
19868d75effSDimitry Andric 
19968d75effSDimitry Andric   return reinterpret_cast<void *>(addr);
20068d75effSDimitry Andric }
20168d75effSDimitry Andric 
20268d75effSDimitry Andric void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
20368d75effSDimitry Andric   return DoAnonymousMmapOrDie(size, mem_type, raw_report, true);
20468d75effSDimitry Andric }
20568d75effSDimitry Andric 
20668d75effSDimitry Andric void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
20768d75effSDimitry Andric   return MmapOrDie(size, mem_type);
20868d75effSDimitry Andric }
20968d75effSDimitry Andric 
21068d75effSDimitry Andric void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
21168d75effSDimitry Andric   return DoAnonymousMmapOrDie(size, mem_type, false, false);
21268d75effSDimitry Andric }
21368d75effSDimitry Andric 
21468d75effSDimitry Andric uptr ReservedAddressRange::Init(uptr init_size, const char *name,
21568d75effSDimitry Andric                                 uptr fixed_addr) {
21668d75effSDimitry Andric   init_size = RoundUpTo(init_size, PAGE_SIZE);
21768d75effSDimitry Andric   DCHECK_EQ(os_handle_, ZX_HANDLE_INVALID);
21868d75effSDimitry Andric   uintptr_t base;
21968d75effSDimitry Andric   zx_handle_t vmar;
22068d75effSDimitry Andric   zx_status_t status =
22168d75effSDimitry Andric       _zx_vmar_allocate(
22268d75effSDimitry Andric           _zx_vmar_root_self(),
22368d75effSDimitry Andric           ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC,
22468d75effSDimitry Andric           0, init_size, &vmar, &base);
22568d75effSDimitry Andric   if (status != ZX_OK)
22668d75effSDimitry Andric     ReportMmapFailureAndDie(init_size, name, "zx_vmar_allocate", status);
22768d75effSDimitry Andric   base_ = reinterpret_cast<void *>(base);
22868d75effSDimitry Andric   size_ = init_size;
22968d75effSDimitry Andric   name_ = name;
23068d75effSDimitry Andric   os_handle_ = vmar;
23168d75effSDimitry Andric 
23268d75effSDimitry Andric   return reinterpret_cast<uptr>(base_);
23368d75effSDimitry Andric }
23468d75effSDimitry Andric 
23568d75effSDimitry Andric static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size,
23668d75effSDimitry Andric                              void *base, const char *name, bool die_for_nomem) {
23768d75effSDimitry Andric   uptr offset = fixed_addr - reinterpret_cast<uptr>(base);
23868d75effSDimitry Andric   map_size = RoundUpTo(map_size, PAGE_SIZE);
23968d75effSDimitry Andric   zx_handle_t vmo;
24068d75effSDimitry Andric   zx_status_t status = _zx_vmo_create(map_size, 0, &vmo);
24168d75effSDimitry Andric   if (status != ZX_OK) {
24268d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY || die_for_nomem)
24368d75effSDimitry Andric       ReportMmapFailureAndDie(map_size, name, "zx_vmo_create", status);
24468d75effSDimitry Andric     return 0;
24568d75effSDimitry Andric   }
24668d75effSDimitry Andric   _zx_object_set_property(vmo, ZX_PROP_NAME, name, internal_strlen(name));
24768d75effSDimitry Andric   DCHECK_GE(base + size_, map_size + offset);
24868d75effSDimitry Andric   uintptr_t addr;
24968d75effSDimitry Andric 
25068d75effSDimitry Andric   status =
25168d75effSDimitry Andric       _zx_vmar_map(vmar, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC,
25268d75effSDimitry Andric                    offset, vmo, 0, map_size, &addr);
25368d75effSDimitry Andric   _zx_handle_close(vmo);
25468d75effSDimitry Andric   if (status != ZX_OK) {
25568d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY || die_for_nomem) {
25668d75effSDimitry Andric       ReportMmapFailureAndDie(map_size, name, "zx_vmar_map", status);
25768d75effSDimitry Andric     }
25868d75effSDimitry Andric     return 0;
25968d75effSDimitry Andric   }
26068d75effSDimitry Andric   IncreaseTotalMmap(map_size);
26168d75effSDimitry Andric   return addr;
26268d75effSDimitry Andric }
26368d75effSDimitry Andric 
26468d75effSDimitry Andric uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size,
26568d75effSDimitry Andric                                const char *name) {
26668d75effSDimitry Andric   return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_,
26768d75effSDimitry Andric                           name_, false);
26868d75effSDimitry Andric }
26968d75effSDimitry Andric 
27068d75effSDimitry Andric uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr map_size,
27168d75effSDimitry Andric                                     const char *name) {
27268d75effSDimitry Andric   return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_,
27368d75effSDimitry Andric                           name_, true);
27468d75effSDimitry Andric }
27568d75effSDimitry Andric 
27668d75effSDimitry Andric void UnmapOrDieVmar(void *addr, uptr size, zx_handle_t target_vmar) {
27768d75effSDimitry Andric   if (!addr || !size) return;
27868d75effSDimitry Andric   size = RoundUpTo(size, PAGE_SIZE);
27968d75effSDimitry Andric 
28068d75effSDimitry Andric   zx_status_t status =
28168d75effSDimitry Andric       _zx_vmar_unmap(target_vmar, reinterpret_cast<uintptr_t>(addr), size);
28268d75effSDimitry Andric   if (status != ZX_OK) {
28368d75effSDimitry Andric     Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
28468d75effSDimitry Andric            SanitizerToolName, size, size, addr);
28568d75effSDimitry Andric     CHECK("unable to unmap" && 0);
28668d75effSDimitry Andric   }
28768d75effSDimitry Andric 
28868d75effSDimitry Andric   DecreaseTotalMmap(size);
28968d75effSDimitry Andric }
29068d75effSDimitry Andric 
29168d75effSDimitry Andric void ReservedAddressRange::Unmap(uptr addr, uptr size) {
29268d75effSDimitry Andric   CHECK_LE(size, size_);
29368d75effSDimitry Andric   const zx_handle_t vmar = static_cast<zx_handle_t>(os_handle_);
29468d75effSDimitry Andric   if (addr == reinterpret_cast<uptr>(base_)) {
29568d75effSDimitry Andric     if (size == size_) {
29668d75effSDimitry Andric       // Destroying the vmar effectively unmaps the whole mapping.
29768d75effSDimitry Andric       _zx_vmar_destroy(vmar);
29868d75effSDimitry Andric       _zx_handle_close(vmar);
29968d75effSDimitry Andric       os_handle_ = static_cast<uptr>(ZX_HANDLE_INVALID);
30068d75effSDimitry Andric       DecreaseTotalMmap(size);
30168d75effSDimitry Andric       return;
30268d75effSDimitry Andric     }
30368d75effSDimitry Andric   } else {
30468d75effSDimitry Andric     CHECK_EQ(addr + size, reinterpret_cast<uptr>(base_) + size_);
30568d75effSDimitry Andric   }
30668d75effSDimitry Andric   // Partial unmapping does not affect the fact that the initial range is still
30768d75effSDimitry Andric   // reserved, and the resulting unmapped memory can't be reused.
30868d75effSDimitry Andric   UnmapOrDieVmar(reinterpret_cast<void *>(addr), size, vmar);
30968d75effSDimitry Andric }
31068d75effSDimitry Andric 
31168d75effSDimitry Andric // This should never be called.
31268d75effSDimitry Andric void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {
31368d75effSDimitry Andric   UNIMPLEMENTED();
31468d75effSDimitry Andric }
31568d75effSDimitry Andric 
31668d75effSDimitry Andric void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
31768d75effSDimitry Andric                                    const char *mem_type) {
31868d75effSDimitry Andric   CHECK_GE(size, PAGE_SIZE);
31968d75effSDimitry Andric   CHECK(IsPowerOfTwo(size));
32068d75effSDimitry Andric   CHECK(IsPowerOfTwo(alignment));
32168d75effSDimitry Andric 
32268d75effSDimitry Andric   zx_handle_t vmo;
32368d75effSDimitry Andric   zx_status_t status = _zx_vmo_create(size, 0, &vmo);
32468d75effSDimitry Andric   if (status != ZX_OK) {
32568d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY)
32668d75effSDimitry Andric       ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status, false);
32768d75effSDimitry Andric     return nullptr;
32868d75effSDimitry Andric   }
32968d75effSDimitry Andric   _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type,
33068d75effSDimitry Andric                           internal_strlen(mem_type));
33168d75effSDimitry Andric 
33268d75effSDimitry Andric   // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that?
33368d75effSDimitry Andric 
33468d75effSDimitry Andric   // Map a larger size to get a chunk of address space big enough that
33568d75effSDimitry Andric   // it surely contains an aligned region of the requested size.  Then
33668d75effSDimitry Andric   // overwrite the aligned middle portion with a mapping from the
33768d75effSDimitry Andric   // beginning of the VMO, and unmap the excess before and after.
33868d75effSDimitry Andric   size_t map_size = size + alignment;
33968d75effSDimitry Andric   uintptr_t addr;
34068d75effSDimitry Andric   status =
34168d75effSDimitry Andric       _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0,
34268d75effSDimitry Andric                    vmo, 0, map_size, &addr);
34368d75effSDimitry Andric   if (status == ZX_OK) {
34468d75effSDimitry Andric     uintptr_t map_addr = addr;
34568d75effSDimitry Andric     uintptr_t map_end = map_addr + map_size;
34668d75effSDimitry Andric     addr = RoundUpTo(map_addr, alignment);
34768d75effSDimitry Andric     uintptr_t end = addr + size;
34868d75effSDimitry Andric     if (addr != map_addr) {
34968d75effSDimitry Andric       zx_info_vmar_t info;
35068d75effSDimitry Andric       status = _zx_object_get_info(_zx_vmar_root_self(), ZX_INFO_VMAR, &info,
35168d75effSDimitry Andric                                    sizeof(info), NULL, NULL);
35268d75effSDimitry Andric       if (status == ZX_OK) {
35368d75effSDimitry Andric         uintptr_t new_addr;
35468d75effSDimitry Andric         status = _zx_vmar_map(
35568d75effSDimitry Andric             _zx_vmar_root_self(),
35668d75effSDimitry Andric             ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC_OVERWRITE,
35768d75effSDimitry Andric             addr - info.base, vmo, 0, size, &new_addr);
35868d75effSDimitry Andric         if (status == ZX_OK) CHECK_EQ(new_addr, addr);
35968d75effSDimitry Andric       }
36068d75effSDimitry Andric     }
36168d75effSDimitry Andric     if (status == ZX_OK && addr != map_addr)
36268d75effSDimitry Andric       status = _zx_vmar_unmap(_zx_vmar_root_self(), map_addr, addr - map_addr);
36368d75effSDimitry Andric     if (status == ZX_OK && end != map_end)
36468d75effSDimitry Andric       status = _zx_vmar_unmap(_zx_vmar_root_self(), end, map_end - end);
36568d75effSDimitry Andric   }
36668d75effSDimitry Andric   _zx_handle_close(vmo);
36768d75effSDimitry Andric 
36868d75effSDimitry Andric   if (status != ZX_OK) {
36968d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY)
37068d75effSDimitry Andric       ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status, false);
37168d75effSDimitry Andric     return nullptr;
37268d75effSDimitry Andric   }
37368d75effSDimitry Andric 
37468d75effSDimitry Andric   IncreaseTotalMmap(size);
37568d75effSDimitry Andric 
37668d75effSDimitry Andric   return reinterpret_cast<void *>(addr);
37768d75effSDimitry Andric }
37868d75effSDimitry Andric 
37968d75effSDimitry Andric void UnmapOrDie(void *addr, uptr size) {
38068d75effSDimitry Andric   UnmapOrDieVmar(addr, size, _zx_vmar_root_self());
38168d75effSDimitry Andric }
38268d75effSDimitry Andric 
38368d75effSDimitry Andric // This is used on the shadow mapping, which cannot be changed.
38468d75effSDimitry Andric // Zircon doesn't have anything like MADV_DONTNEED.
38568d75effSDimitry Andric void ReleaseMemoryPagesToOS(uptr beg, uptr end) {}
38668d75effSDimitry Andric 
38768d75effSDimitry Andric void DumpProcessMap() {
38868d75effSDimitry Andric   // TODO(mcgrathr): write it
38968d75effSDimitry Andric   return;
39068d75effSDimitry Andric }
39168d75effSDimitry Andric 
39268d75effSDimitry Andric bool IsAccessibleMemoryRange(uptr beg, uptr size) {
39368d75effSDimitry Andric   // TODO(mcgrathr): Figure out a better way.
39468d75effSDimitry Andric   zx_handle_t vmo;
39568d75effSDimitry Andric   zx_status_t status = _zx_vmo_create(size, 0, &vmo);
39668d75effSDimitry Andric   if (status == ZX_OK) {
39768d75effSDimitry Andric     status = _zx_vmo_write(vmo, reinterpret_cast<const void *>(beg), 0, size);
39868d75effSDimitry Andric     _zx_handle_close(vmo);
39968d75effSDimitry Andric   }
40068d75effSDimitry Andric   return status == ZX_OK;
40168d75effSDimitry Andric }
40268d75effSDimitry Andric 
40368d75effSDimitry Andric // FIXME implement on this platform.
40468d75effSDimitry Andric void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {}
40568d75effSDimitry Andric 
40668d75effSDimitry Andric bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
40768d75effSDimitry Andric                       uptr *read_len, uptr max_len, error_t *errno_p) {
40868d75effSDimitry Andric   zx_handle_t vmo;
40968d75effSDimitry Andric   zx_status_t status = __sanitizer_get_configuration(file_name, &vmo);
41068d75effSDimitry Andric   if (status == ZX_OK) {
41168d75effSDimitry Andric     uint64_t vmo_size;
41268d75effSDimitry Andric     status = _zx_vmo_get_size(vmo, &vmo_size);
41368d75effSDimitry Andric     if (status == ZX_OK) {
41468d75effSDimitry Andric       if (vmo_size < max_len) max_len = vmo_size;
41568d75effSDimitry Andric       size_t map_size = RoundUpTo(max_len, PAGE_SIZE);
41668d75effSDimitry Andric       uintptr_t addr;
41768d75effSDimitry Andric       status = _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ, 0, vmo, 0,
41868d75effSDimitry Andric                             map_size, &addr);
41968d75effSDimitry Andric       if (status == ZX_OK) {
42068d75effSDimitry Andric         *buff = reinterpret_cast<char *>(addr);
42168d75effSDimitry Andric         *buff_size = map_size;
42268d75effSDimitry Andric         *read_len = max_len;
42368d75effSDimitry Andric       }
42468d75effSDimitry Andric     }
42568d75effSDimitry Andric     _zx_handle_close(vmo);
42668d75effSDimitry Andric   }
42768d75effSDimitry Andric   if (status != ZX_OK && errno_p) *errno_p = status;
42868d75effSDimitry Andric   return status == ZX_OK;
42968d75effSDimitry Andric }
43068d75effSDimitry Andric 
43168d75effSDimitry Andric void RawWrite(const char *buffer) {
43268d75effSDimitry Andric   constexpr size_t size = 128;
43368d75effSDimitry Andric   static _Thread_local char line[size];
43468d75effSDimitry Andric   static _Thread_local size_t lastLineEnd = 0;
43568d75effSDimitry Andric   static _Thread_local size_t cur = 0;
43668d75effSDimitry Andric 
43768d75effSDimitry Andric   while (*buffer) {
43868d75effSDimitry Andric     if (cur >= size) {
43968d75effSDimitry Andric       if (lastLineEnd == 0)
44068d75effSDimitry Andric         lastLineEnd = size;
44168d75effSDimitry Andric       __sanitizer_log_write(line, lastLineEnd);
44268d75effSDimitry Andric       internal_memmove(line, line + lastLineEnd, cur - lastLineEnd);
44368d75effSDimitry Andric       cur = cur - lastLineEnd;
44468d75effSDimitry Andric       lastLineEnd = 0;
44568d75effSDimitry Andric     }
44668d75effSDimitry Andric     if (*buffer == '\n')
44768d75effSDimitry Andric       lastLineEnd = cur + 1;
44868d75effSDimitry Andric     line[cur++] = *buffer++;
44968d75effSDimitry Andric   }
45068d75effSDimitry Andric   // Flush all complete lines before returning.
45168d75effSDimitry Andric   if (lastLineEnd != 0) {
45268d75effSDimitry Andric     __sanitizer_log_write(line, lastLineEnd);
45368d75effSDimitry Andric     internal_memmove(line, line + lastLineEnd, cur - lastLineEnd);
45468d75effSDimitry Andric     cur = cur - lastLineEnd;
45568d75effSDimitry Andric     lastLineEnd = 0;
45668d75effSDimitry Andric   }
45768d75effSDimitry Andric }
45868d75effSDimitry Andric 
45968d75effSDimitry Andric void CatastrophicErrorWrite(const char *buffer, uptr length) {
46068d75effSDimitry Andric   __sanitizer_log_write(buffer, length);
46168d75effSDimitry Andric }
46268d75effSDimitry Andric 
46368d75effSDimitry Andric char **StoredArgv;
46468d75effSDimitry Andric char **StoredEnviron;
46568d75effSDimitry Andric 
46668d75effSDimitry Andric char **GetArgv() { return StoredArgv; }
46768d75effSDimitry Andric char **GetEnviron() { return StoredEnviron; }
46868d75effSDimitry Andric 
46968d75effSDimitry Andric const char *GetEnv(const char *name) {
47068d75effSDimitry Andric   if (StoredEnviron) {
47168d75effSDimitry Andric     uptr NameLen = internal_strlen(name);
47268d75effSDimitry Andric     for (char **Env = StoredEnviron; *Env != 0; Env++) {
47368d75effSDimitry Andric       if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=')
47468d75effSDimitry Andric         return (*Env) + NameLen + 1;
47568d75effSDimitry Andric     }
47668d75effSDimitry Andric   }
47768d75effSDimitry Andric   return nullptr;
47868d75effSDimitry Andric }
47968d75effSDimitry Andric 
48068d75effSDimitry Andric uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) {
48168d75effSDimitry Andric   const char *argv0 = "<UNKNOWN>";
48268d75effSDimitry Andric   if (StoredArgv && StoredArgv[0]) {
48368d75effSDimitry Andric     argv0 = StoredArgv[0];
48468d75effSDimitry Andric   }
48568d75effSDimitry Andric   internal_strncpy(buf, argv0, buf_len);
48668d75effSDimitry Andric   return internal_strlen(buf);
48768d75effSDimitry Andric }
48868d75effSDimitry Andric 
48968d75effSDimitry Andric uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
49068d75effSDimitry Andric   return ReadBinaryName(buf, buf_len);
49168d75effSDimitry Andric }
49268d75effSDimitry Andric 
49368d75effSDimitry Andric uptr MainThreadStackBase, MainThreadStackSize;
49468d75effSDimitry Andric 
49568d75effSDimitry Andric bool GetRandom(void *buffer, uptr length, bool blocking) {
49668d75effSDimitry Andric   CHECK_LE(length, ZX_CPRNG_DRAW_MAX_LEN);
49768d75effSDimitry Andric   _zx_cprng_draw(buffer, length);
49868d75effSDimitry Andric   return true;
49968d75effSDimitry Andric }
50068d75effSDimitry Andric 
50168d75effSDimitry Andric u32 GetNumberOfCPUs() {
50268d75effSDimitry Andric   return zx_system_get_num_cpus();
50368d75effSDimitry Andric }
50468d75effSDimitry Andric 
50568d75effSDimitry Andric uptr GetRSS() { UNIMPLEMENTED(); }
50668d75effSDimitry Andric 
50768d75effSDimitry Andric }  // namespace __sanitizer
50868d75effSDimitry Andric 
50968d75effSDimitry Andric using namespace __sanitizer;
51068d75effSDimitry Andric 
51168d75effSDimitry Andric extern "C" {
51268d75effSDimitry Andric void __sanitizer_startup_hook(int argc, char **argv, char **envp,
51368d75effSDimitry Andric                               void *stack_base, size_t stack_size) {
51468d75effSDimitry Andric   __sanitizer::StoredArgv = argv;
51568d75effSDimitry Andric   __sanitizer::StoredEnviron = envp;
51668d75effSDimitry Andric   __sanitizer::MainThreadStackBase = reinterpret_cast<uintptr_t>(stack_base);
51768d75effSDimitry Andric   __sanitizer::MainThreadStackSize = stack_size;
51868d75effSDimitry Andric }
51968d75effSDimitry Andric 
52068d75effSDimitry Andric void __sanitizer_set_report_path(const char *path) {
52168d75effSDimitry Andric   // Handle the initialization code in each sanitizer, but no other calls.
52268d75effSDimitry Andric   // This setting is never consulted on Fuchsia.
52368d75effSDimitry Andric   DCHECK_EQ(path, common_flags()->log_path);
52468d75effSDimitry Andric }
52568d75effSDimitry Andric 
52668d75effSDimitry Andric void __sanitizer_set_report_fd(void *fd) {
52768d75effSDimitry Andric   UNREACHABLE("not available on Fuchsia");
52868d75effSDimitry Andric }
52968d75effSDimitry Andric }  // extern "C"
53068d75effSDimitry Andric 
53168d75effSDimitry Andric #endif  // SANITIZER_FUCHSIA
532