xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
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 <pthread.h>
1868d75effSDimitry Andric #include <stdlib.h>
1968d75effSDimitry Andric #include <unistd.h>
2068d75effSDimitry Andric #include <zircon/errors.h>
2168d75effSDimitry Andric #include <zircon/process.h>
2268d75effSDimitry Andric #include <zircon/syscalls.h>
23e8d8bef9SDimitry Andric #include <zircon/utc.h>
24e8d8bef9SDimitry Andric 
25e8d8bef9SDimitry Andric #include "sanitizer_common.h"
26e8d8bef9SDimitry Andric #include "sanitizer_libc.h"
27e8d8bef9SDimitry Andric #include "sanitizer_mutex.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 
39*fe6060f1SDimitry Andric void internal_usleep(u64 useconds) {
40*fe6060f1SDimitry Andric   zx_status_t status = _zx_nanosleep(_zx_deadline_after(ZX_USEC(useconds)));
4168d75effSDimitry Andric   CHECK_EQ(status, ZX_OK);
4268d75effSDimitry Andric }
4368d75effSDimitry Andric 
4468d75effSDimitry Andric u64 NanoTime() {
45e8d8bef9SDimitry Andric   zx_handle_t utc_clock = _zx_utc_reference_get();
46e8d8bef9SDimitry Andric   CHECK_NE(utc_clock, ZX_HANDLE_INVALID);
4768d75effSDimitry Andric   zx_time_t time;
48e8d8bef9SDimitry Andric   zx_status_t status = _zx_clock_read(utc_clock, &time);
4968d75effSDimitry Andric   CHECK_EQ(status, ZX_OK);
5068d75effSDimitry Andric   return time;
5168d75effSDimitry Andric }
5268d75effSDimitry Andric 
5368d75effSDimitry Andric u64 MonotonicNanoTime() { return _zx_clock_get_monotonic(); }
5468d75effSDimitry Andric 
5568d75effSDimitry Andric uptr internal_getpid() {
5668d75effSDimitry Andric   zx_info_handle_basic_t info;
5768d75effSDimitry Andric   zx_status_t status =
5868d75effSDimitry Andric       _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &info,
5968d75effSDimitry Andric                           sizeof(info), NULL, NULL);
6068d75effSDimitry Andric   CHECK_EQ(status, ZX_OK);
6168d75effSDimitry Andric   uptr pid = static_cast<uptr>(info.koid);
6268d75effSDimitry Andric   CHECK_EQ(pid, info.koid);
6368d75effSDimitry Andric   return pid;
6468d75effSDimitry Andric }
6568d75effSDimitry Andric 
66*fe6060f1SDimitry Andric int internal_dlinfo(void *handle, int request, void *p) { UNIMPLEMENTED(); }
675ffd83dbSDimitry Andric 
6868d75effSDimitry Andric uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); }
6968d75effSDimitry Andric 
7068d75effSDimitry Andric tid_t GetTid() { return GetThreadSelf(); }
7168d75effSDimitry Andric 
7268d75effSDimitry Andric void Abort() { abort(); }
7368d75effSDimitry Andric 
7468d75effSDimitry Andric int Atexit(void (*function)(void)) { return atexit(function); }
7568d75effSDimitry Andric 
7668d75effSDimitry Andric void GetThreadStackTopAndBottom(bool, uptr *stack_top, uptr *stack_bottom) {
7768d75effSDimitry Andric   pthread_attr_t attr;
7868d75effSDimitry Andric   CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
7968d75effSDimitry Andric   void *base;
8068d75effSDimitry Andric   size_t size;
8168d75effSDimitry Andric   CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0);
8268d75effSDimitry Andric   CHECK_EQ(pthread_attr_destroy(&attr), 0);
8368d75effSDimitry Andric 
8468d75effSDimitry Andric   *stack_bottom = reinterpret_cast<uptr>(base);
8568d75effSDimitry Andric   *stack_top = *stack_bottom + size;
8668d75effSDimitry Andric }
8768d75effSDimitry Andric 
8868d75effSDimitry Andric void InitializePlatformEarly() {}
8968d75effSDimitry Andric void MaybeReexec() {}
9068d75effSDimitry Andric void CheckASLR() {}
9168d75effSDimitry Andric void CheckMPROTECT() {}
9268d75effSDimitry Andric void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {}
9368d75effSDimitry Andric void DisableCoreDumperIfNecessary() {}
9468d75effSDimitry Andric void InstallDeadlySignalHandlers(SignalHandlerType handler) {}
9568d75effSDimitry Andric void SetAlternateSignalStack() {}
9668d75effSDimitry Andric void UnsetAlternateSignalStack() {}
9768d75effSDimitry Andric void InitTlsSize() {}
9868d75effSDimitry Andric 
9968d75effSDimitry Andric bool SignalContext::IsStackOverflow() const { return false; }
10068d75effSDimitry Andric void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); }
10168d75effSDimitry Andric const char *SignalContext::Describe() const { UNIMPLEMENTED(); }
10268d75effSDimitry Andric 
103*fe6060f1SDimitry Andric void FutexWait(atomic_uint32_t *p, u32 cmp) {
104*fe6060f1SDimitry Andric   zx_status_t status = _zx_futex_wait(reinterpret_cast<zx_futex_t *>(p), cmp,
105*fe6060f1SDimitry Andric                                       ZX_HANDLE_INVALID, ZX_TIME_INFINITE);
106*fe6060f1SDimitry Andric   if (status != ZX_ERR_BAD_STATE)  // Normal race.
107*fe6060f1SDimitry Andric     CHECK_EQ(status, ZX_OK);
108*fe6060f1SDimitry Andric }
109*fe6060f1SDimitry Andric 
110*fe6060f1SDimitry Andric void FutexWake(atomic_uint32_t *p, u32 count) {
111*fe6060f1SDimitry Andric   zx_status_t status = _zx_futex_wake(reinterpret_cast<zx_futex_t *>(p), count);
112*fe6060f1SDimitry Andric   CHECK_EQ(status, ZX_OK);
113*fe6060f1SDimitry Andric }
114*fe6060f1SDimitry Andric 
11568d75effSDimitry Andric enum MutexState : int { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 };
11668d75effSDimitry Andric 
11768d75effSDimitry Andric BlockingMutex::BlockingMutex() {
11868d75effSDimitry Andric   // NOTE!  It's important that this use internal_memset, because plain
11968d75effSDimitry Andric   // memset might be intercepted (e.g., actually be __asan_memset).
12068d75effSDimitry Andric   // Defining this so the compiler initializes each field, e.g.:
12168d75effSDimitry Andric   //   BlockingMutex::BlockingMutex() : BlockingMutex(LINKER_INITIALIZED) {}
12268d75effSDimitry Andric   // might result in the compiler generating a call to memset, which would
12368d75effSDimitry Andric   // have the same problem.
12468d75effSDimitry Andric   internal_memset(this, 0, sizeof(*this));
12568d75effSDimitry Andric }
12668d75effSDimitry Andric 
12768d75effSDimitry Andric void BlockingMutex::Lock() {
12868d75effSDimitry Andric   CHECK_EQ(owner_, 0);
12968d75effSDimitry Andric   atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
13068d75effSDimitry Andric   if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
13168d75effSDimitry Andric     return;
13268d75effSDimitry Andric   while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) {
13368d75effSDimitry Andric     zx_status_t status =
13468d75effSDimitry Andric         _zx_futex_wait(reinterpret_cast<zx_futex_t *>(m), MtxSleeping,
13568d75effSDimitry Andric                        ZX_HANDLE_INVALID, ZX_TIME_INFINITE);
13668d75effSDimitry Andric     if (status != ZX_ERR_BAD_STATE)  // Normal race.
13768d75effSDimitry Andric       CHECK_EQ(status, ZX_OK);
13868d75effSDimitry Andric   }
13968d75effSDimitry Andric }
14068d75effSDimitry Andric 
14168d75effSDimitry Andric void BlockingMutex::Unlock() {
14268d75effSDimitry Andric   atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
14368d75effSDimitry Andric   u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release);
14468d75effSDimitry Andric   CHECK_NE(v, MtxUnlocked);
14568d75effSDimitry Andric   if (v == MtxSleeping) {
14668d75effSDimitry Andric     zx_status_t status = _zx_futex_wake(reinterpret_cast<zx_futex_t *>(m), 1);
14768d75effSDimitry Andric     CHECK_EQ(status, ZX_OK);
14868d75effSDimitry Andric   }
14968d75effSDimitry Andric }
15068d75effSDimitry Andric 
151*fe6060f1SDimitry Andric void BlockingMutex::CheckLocked() const {
152*fe6060f1SDimitry Andric   auto m = reinterpret_cast<atomic_uint32_t const *>(&opaque_storage_);
15368d75effSDimitry Andric   CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
15468d75effSDimitry Andric }
15568d75effSDimitry Andric 
156*fe6060f1SDimitry Andric uptr GetPageSize() { return _zx_system_get_page_size(); }
15768d75effSDimitry Andric 
158*fe6060f1SDimitry Andric uptr GetMmapGranularity() { return _zx_system_get_page_size(); }
15968d75effSDimitry Andric 
16068d75effSDimitry Andric sanitizer_shadow_bounds_t ShadowBounds;
16168d75effSDimitry Andric 
162*fe6060f1SDimitry Andric void InitShadowBounds() { ShadowBounds = __sanitizer_shadow_bounds(); }
163*fe6060f1SDimitry Andric 
16468d75effSDimitry Andric uptr GetMaxUserVirtualAddress() {
165*fe6060f1SDimitry Andric   InitShadowBounds();
16668d75effSDimitry Andric   return ShadowBounds.memory_limit - 1;
16768d75effSDimitry Andric }
16868d75effSDimitry Andric 
16968d75effSDimitry Andric uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); }
17068d75effSDimitry Andric 
17168d75effSDimitry Andric static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type,
17268d75effSDimitry Andric                                   bool raw_report, bool die_for_nomem) {
173*fe6060f1SDimitry Andric   size = RoundUpTo(size, GetPageSize());
17468d75effSDimitry Andric 
17568d75effSDimitry Andric   zx_handle_t vmo;
17668d75effSDimitry Andric   zx_status_t status = _zx_vmo_create(size, 0, &vmo);
17768d75effSDimitry Andric   if (status != ZX_OK) {
17868d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY || die_for_nomem)
17968d75effSDimitry Andric       ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status,
18068d75effSDimitry Andric                               raw_report);
18168d75effSDimitry Andric     return nullptr;
18268d75effSDimitry Andric   }
18368d75effSDimitry Andric   _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type,
18468d75effSDimitry Andric                           internal_strlen(mem_type));
18568d75effSDimitry Andric 
18668d75effSDimitry Andric   // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that?
18768d75effSDimitry Andric   uintptr_t addr;
18868d75effSDimitry Andric   status =
18968d75effSDimitry Andric       _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0,
19068d75effSDimitry Andric                    vmo, 0, size, &addr);
19168d75effSDimitry Andric   _zx_handle_close(vmo);
19268d75effSDimitry Andric 
19368d75effSDimitry Andric   if (status != ZX_OK) {
19468d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY || die_for_nomem)
19568d75effSDimitry Andric       ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status,
19668d75effSDimitry Andric                               raw_report);
19768d75effSDimitry Andric     return nullptr;
19868d75effSDimitry Andric   }
19968d75effSDimitry Andric 
20068d75effSDimitry Andric   IncreaseTotalMmap(size);
20168d75effSDimitry Andric 
20268d75effSDimitry Andric   return reinterpret_cast<void *>(addr);
20368d75effSDimitry Andric }
20468d75effSDimitry Andric 
20568d75effSDimitry Andric void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
20668d75effSDimitry Andric   return DoAnonymousMmapOrDie(size, mem_type, raw_report, true);
20768d75effSDimitry Andric }
20868d75effSDimitry Andric 
20968d75effSDimitry Andric void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
21068d75effSDimitry Andric   return MmapOrDie(size, mem_type);
21168d75effSDimitry Andric }
21268d75effSDimitry Andric 
21368d75effSDimitry Andric void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
21468d75effSDimitry Andric   return DoAnonymousMmapOrDie(size, mem_type, false, false);
21568d75effSDimitry Andric }
21668d75effSDimitry Andric 
21768d75effSDimitry Andric uptr ReservedAddressRange::Init(uptr init_size, const char *name,
21868d75effSDimitry Andric                                 uptr fixed_addr) {
219*fe6060f1SDimitry Andric   init_size = RoundUpTo(init_size, GetPageSize());
22068d75effSDimitry Andric   DCHECK_EQ(os_handle_, ZX_HANDLE_INVALID);
22168d75effSDimitry Andric   uintptr_t base;
22268d75effSDimitry Andric   zx_handle_t vmar;
223*fe6060f1SDimitry Andric   zx_status_t status = _zx_vmar_allocate(
22468d75effSDimitry Andric       _zx_vmar_root_self(),
225*fe6060f1SDimitry Andric       ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0,
226*fe6060f1SDimitry Andric       init_size, &vmar, &base);
22768d75effSDimitry Andric   if (status != ZX_OK)
22868d75effSDimitry Andric     ReportMmapFailureAndDie(init_size, name, "zx_vmar_allocate", status);
22968d75effSDimitry Andric   base_ = reinterpret_cast<void *>(base);
23068d75effSDimitry Andric   size_ = init_size;
23168d75effSDimitry Andric   name_ = name;
23268d75effSDimitry Andric   os_handle_ = vmar;
23368d75effSDimitry Andric 
23468d75effSDimitry Andric   return reinterpret_cast<uptr>(base_);
23568d75effSDimitry Andric }
23668d75effSDimitry Andric 
23768d75effSDimitry Andric static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size,
23868d75effSDimitry Andric                              void *base, const char *name, bool die_for_nomem) {
23968d75effSDimitry Andric   uptr offset = fixed_addr - reinterpret_cast<uptr>(base);
240*fe6060f1SDimitry Andric   map_size = RoundUpTo(map_size, GetPageSize());
24168d75effSDimitry Andric   zx_handle_t vmo;
24268d75effSDimitry Andric   zx_status_t status = _zx_vmo_create(map_size, 0, &vmo);
24368d75effSDimitry Andric   if (status != ZX_OK) {
24468d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY || die_for_nomem)
24568d75effSDimitry Andric       ReportMmapFailureAndDie(map_size, name, "zx_vmo_create", status);
24668d75effSDimitry Andric     return 0;
24768d75effSDimitry Andric   }
24868d75effSDimitry Andric   _zx_object_set_property(vmo, ZX_PROP_NAME, name, internal_strlen(name));
24968d75effSDimitry Andric   DCHECK_GE(base + size_, map_size + offset);
25068d75effSDimitry Andric   uintptr_t addr;
25168d75effSDimitry Andric 
25268d75effSDimitry Andric   status =
25368d75effSDimitry Andric       _zx_vmar_map(vmar, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC,
25468d75effSDimitry Andric                    offset, vmo, 0, map_size, &addr);
25568d75effSDimitry Andric   _zx_handle_close(vmo);
25668d75effSDimitry Andric   if (status != ZX_OK) {
25768d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY || die_for_nomem) {
25868d75effSDimitry Andric       ReportMmapFailureAndDie(map_size, name, "zx_vmar_map", status);
25968d75effSDimitry Andric     }
26068d75effSDimitry Andric     return 0;
26168d75effSDimitry Andric   }
26268d75effSDimitry Andric   IncreaseTotalMmap(map_size);
26368d75effSDimitry Andric   return addr;
26468d75effSDimitry Andric }
26568d75effSDimitry Andric 
26668d75effSDimitry Andric uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size,
26768d75effSDimitry Andric                                const char *name) {
268*fe6060f1SDimitry Andric   return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, name_,
269*fe6060f1SDimitry Andric                           false);
27068d75effSDimitry Andric }
27168d75effSDimitry Andric 
27268d75effSDimitry Andric uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr map_size,
27368d75effSDimitry Andric                                     const char *name) {
274*fe6060f1SDimitry Andric   return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, name_, true);
27568d75effSDimitry Andric }
27668d75effSDimitry Andric 
27768d75effSDimitry Andric void UnmapOrDieVmar(void *addr, uptr size, zx_handle_t target_vmar) {
278*fe6060f1SDimitry Andric   if (!addr || !size)
279*fe6060f1SDimitry Andric     return;
280*fe6060f1SDimitry Andric   size = RoundUpTo(size, GetPageSize());
28168d75effSDimitry Andric 
28268d75effSDimitry Andric   zx_status_t status =
28368d75effSDimitry Andric       _zx_vmar_unmap(target_vmar, reinterpret_cast<uintptr_t>(addr), size);
28468d75effSDimitry Andric   if (status != ZX_OK) {
28568d75effSDimitry Andric     Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
28668d75effSDimitry Andric            SanitizerToolName, size, size, addr);
28768d75effSDimitry Andric     CHECK("unable to unmap" && 0);
28868d75effSDimitry Andric   }
28968d75effSDimitry Andric 
29068d75effSDimitry Andric   DecreaseTotalMmap(size);
29168d75effSDimitry Andric }
29268d75effSDimitry Andric 
29368d75effSDimitry Andric void ReservedAddressRange::Unmap(uptr addr, uptr size) {
29468d75effSDimitry Andric   CHECK_LE(size, size_);
29568d75effSDimitry Andric   const zx_handle_t vmar = static_cast<zx_handle_t>(os_handle_);
29668d75effSDimitry Andric   if (addr == reinterpret_cast<uptr>(base_)) {
29768d75effSDimitry Andric     if (size == size_) {
29868d75effSDimitry Andric       // Destroying the vmar effectively unmaps the whole mapping.
29968d75effSDimitry Andric       _zx_vmar_destroy(vmar);
30068d75effSDimitry Andric       _zx_handle_close(vmar);
30168d75effSDimitry Andric       os_handle_ = static_cast<uptr>(ZX_HANDLE_INVALID);
30268d75effSDimitry Andric       DecreaseTotalMmap(size);
30368d75effSDimitry Andric       return;
30468d75effSDimitry Andric     }
30568d75effSDimitry Andric   } else {
30668d75effSDimitry Andric     CHECK_EQ(addr + size, reinterpret_cast<uptr>(base_) + size_);
30768d75effSDimitry Andric   }
30868d75effSDimitry Andric   // Partial unmapping does not affect the fact that the initial range is still
30968d75effSDimitry Andric   // reserved, and the resulting unmapped memory can't be reused.
31068d75effSDimitry Andric   UnmapOrDieVmar(reinterpret_cast<void *>(addr), size, vmar);
31168d75effSDimitry Andric }
31268d75effSDimitry Andric 
31368d75effSDimitry Andric // This should never be called.
31468d75effSDimitry Andric void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {
31568d75effSDimitry Andric   UNIMPLEMENTED();
31668d75effSDimitry Andric }
31768d75effSDimitry Andric 
31868d75effSDimitry Andric void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
31968d75effSDimitry Andric                                    const char *mem_type) {
320*fe6060f1SDimitry Andric   CHECK_GE(size, GetPageSize());
32168d75effSDimitry Andric   CHECK(IsPowerOfTwo(size));
32268d75effSDimitry Andric   CHECK(IsPowerOfTwo(alignment));
32368d75effSDimitry Andric 
32468d75effSDimitry Andric   zx_handle_t vmo;
32568d75effSDimitry Andric   zx_status_t status = _zx_vmo_create(size, 0, &vmo);
32668d75effSDimitry Andric   if (status != ZX_OK) {
32768d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY)
32868d75effSDimitry Andric       ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status, false);
32968d75effSDimitry Andric     return nullptr;
33068d75effSDimitry Andric   }
33168d75effSDimitry Andric   _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type,
33268d75effSDimitry Andric                           internal_strlen(mem_type));
33368d75effSDimitry Andric 
33468d75effSDimitry Andric   // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that?
33568d75effSDimitry Andric 
33668d75effSDimitry Andric   // Map a larger size to get a chunk of address space big enough that
33768d75effSDimitry Andric   // it surely contains an aligned region of the requested size.  Then
33868d75effSDimitry Andric   // overwrite the aligned middle portion with a mapping from the
33968d75effSDimitry Andric   // beginning of the VMO, and unmap the excess before and after.
34068d75effSDimitry Andric   size_t map_size = size + alignment;
34168d75effSDimitry Andric   uintptr_t addr;
34268d75effSDimitry Andric   status =
34368d75effSDimitry Andric       _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0,
34468d75effSDimitry Andric                    vmo, 0, map_size, &addr);
34568d75effSDimitry Andric   if (status == ZX_OK) {
34668d75effSDimitry Andric     uintptr_t map_addr = addr;
34768d75effSDimitry Andric     uintptr_t map_end = map_addr + map_size;
34868d75effSDimitry Andric     addr = RoundUpTo(map_addr, alignment);
34968d75effSDimitry Andric     uintptr_t end = addr + size;
35068d75effSDimitry Andric     if (addr != map_addr) {
35168d75effSDimitry Andric       zx_info_vmar_t info;
35268d75effSDimitry Andric       status = _zx_object_get_info(_zx_vmar_root_self(), ZX_INFO_VMAR, &info,
35368d75effSDimitry Andric                                    sizeof(info), NULL, NULL);
35468d75effSDimitry Andric       if (status == ZX_OK) {
35568d75effSDimitry Andric         uintptr_t new_addr;
35668d75effSDimitry Andric         status = _zx_vmar_map(
35768d75effSDimitry Andric             _zx_vmar_root_self(),
35868d75effSDimitry Andric             ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC_OVERWRITE,
35968d75effSDimitry Andric             addr - info.base, vmo, 0, size, &new_addr);
360*fe6060f1SDimitry Andric         if (status == ZX_OK)
361*fe6060f1SDimitry Andric           CHECK_EQ(new_addr, addr);
36268d75effSDimitry Andric       }
36368d75effSDimitry Andric     }
36468d75effSDimitry Andric     if (status == ZX_OK && addr != map_addr)
36568d75effSDimitry Andric       status = _zx_vmar_unmap(_zx_vmar_root_self(), map_addr, addr - map_addr);
36668d75effSDimitry Andric     if (status == ZX_OK && end != map_end)
36768d75effSDimitry Andric       status = _zx_vmar_unmap(_zx_vmar_root_self(), end, map_end - end);
36868d75effSDimitry Andric   }
36968d75effSDimitry Andric   _zx_handle_close(vmo);
37068d75effSDimitry Andric 
37168d75effSDimitry Andric   if (status != ZX_OK) {
37268d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY)
37368d75effSDimitry Andric       ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status, false);
37468d75effSDimitry Andric     return nullptr;
37568d75effSDimitry Andric   }
37668d75effSDimitry Andric 
37768d75effSDimitry Andric   IncreaseTotalMmap(size);
37868d75effSDimitry Andric 
37968d75effSDimitry Andric   return reinterpret_cast<void *>(addr);
38068d75effSDimitry Andric }
38168d75effSDimitry Andric 
38268d75effSDimitry Andric void UnmapOrDie(void *addr, uptr size) {
38368d75effSDimitry Andric   UnmapOrDieVmar(addr, size, _zx_vmar_root_self());
38468d75effSDimitry Andric }
38568d75effSDimitry Andric 
386*fe6060f1SDimitry Andric void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
387*fe6060f1SDimitry Andric   uptr beg_aligned = RoundUpTo(beg, GetPageSize());
388*fe6060f1SDimitry Andric   uptr end_aligned = RoundDownTo(end, GetPageSize());
389*fe6060f1SDimitry Andric   if (beg_aligned < end_aligned) {
390*fe6060f1SDimitry Andric     zx_handle_t root_vmar = _zx_vmar_root_self();
391*fe6060f1SDimitry Andric     CHECK_NE(root_vmar, ZX_HANDLE_INVALID);
392*fe6060f1SDimitry Andric     zx_status_t status =
393*fe6060f1SDimitry Andric         _zx_vmar_op_range(root_vmar, ZX_VMAR_OP_DECOMMIT, beg_aligned,
394*fe6060f1SDimitry Andric                           end_aligned - beg_aligned, nullptr, 0);
395*fe6060f1SDimitry Andric     CHECK_EQ(status, ZX_OK);
396*fe6060f1SDimitry Andric   }
397*fe6060f1SDimitry Andric }
39868d75effSDimitry Andric 
39968d75effSDimitry Andric void DumpProcessMap() {
40068d75effSDimitry Andric   // TODO(mcgrathr): write it
40168d75effSDimitry Andric   return;
40268d75effSDimitry Andric }
40368d75effSDimitry Andric 
40468d75effSDimitry Andric bool IsAccessibleMemoryRange(uptr beg, uptr size) {
40568d75effSDimitry Andric   // TODO(mcgrathr): Figure out a better way.
40668d75effSDimitry Andric   zx_handle_t vmo;
40768d75effSDimitry Andric   zx_status_t status = _zx_vmo_create(size, 0, &vmo);
40868d75effSDimitry Andric   if (status == ZX_OK) {
40968d75effSDimitry Andric     status = _zx_vmo_write(vmo, reinterpret_cast<const void *>(beg), 0, size);
41068d75effSDimitry Andric     _zx_handle_close(vmo);
41168d75effSDimitry Andric   }
41268d75effSDimitry Andric   return status == ZX_OK;
41368d75effSDimitry Andric }
41468d75effSDimitry Andric 
41568d75effSDimitry Andric // FIXME implement on this platform.
41668d75effSDimitry Andric void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {}
41768d75effSDimitry Andric 
41868d75effSDimitry Andric bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
41968d75effSDimitry Andric                       uptr *read_len, uptr max_len, error_t *errno_p) {
42068d75effSDimitry Andric   zx_handle_t vmo;
42168d75effSDimitry Andric   zx_status_t status = __sanitizer_get_configuration(file_name, &vmo);
42268d75effSDimitry Andric   if (status == ZX_OK) {
42368d75effSDimitry Andric     uint64_t vmo_size;
42468d75effSDimitry Andric     status = _zx_vmo_get_size(vmo, &vmo_size);
42568d75effSDimitry Andric     if (status == ZX_OK) {
426*fe6060f1SDimitry Andric       if (vmo_size < max_len)
427*fe6060f1SDimitry Andric         max_len = vmo_size;
428*fe6060f1SDimitry Andric       size_t map_size = RoundUpTo(max_len, GetPageSize());
42968d75effSDimitry Andric       uintptr_t addr;
43068d75effSDimitry Andric       status = _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ, 0, vmo, 0,
43168d75effSDimitry Andric                             map_size, &addr);
43268d75effSDimitry Andric       if (status == ZX_OK) {
43368d75effSDimitry Andric         *buff = reinterpret_cast<char *>(addr);
43468d75effSDimitry Andric         *buff_size = map_size;
43568d75effSDimitry Andric         *read_len = max_len;
43668d75effSDimitry Andric       }
43768d75effSDimitry Andric     }
43868d75effSDimitry Andric     _zx_handle_close(vmo);
43968d75effSDimitry Andric   }
440*fe6060f1SDimitry Andric   if (status != ZX_OK && errno_p)
441*fe6060f1SDimitry Andric     *errno_p = status;
44268d75effSDimitry Andric   return status == ZX_OK;
44368d75effSDimitry Andric }
44468d75effSDimitry Andric 
44568d75effSDimitry Andric void RawWrite(const char *buffer) {
44668d75effSDimitry Andric   constexpr size_t size = 128;
44768d75effSDimitry Andric   static _Thread_local char line[size];
44868d75effSDimitry Andric   static _Thread_local size_t lastLineEnd = 0;
44968d75effSDimitry Andric   static _Thread_local size_t cur = 0;
45068d75effSDimitry Andric 
45168d75effSDimitry Andric   while (*buffer) {
45268d75effSDimitry Andric     if (cur >= size) {
45368d75effSDimitry Andric       if (lastLineEnd == 0)
45468d75effSDimitry Andric         lastLineEnd = size;
45568d75effSDimitry Andric       __sanitizer_log_write(line, lastLineEnd);
45668d75effSDimitry Andric       internal_memmove(line, line + lastLineEnd, cur - lastLineEnd);
45768d75effSDimitry Andric       cur = cur - lastLineEnd;
45868d75effSDimitry Andric       lastLineEnd = 0;
45968d75effSDimitry Andric     }
46068d75effSDimitry Andric     if (*buffer == '\n')
46168d75effSDimitry Andric       lastLineEnd = cur + 1;
46268d75effSDimitry Andric     line[cur++] = *buffer++;
46368d75effSDimitry Andric   }
46468d75effSDimitry Andric   // Flush all complete lines before returning.
46568d75effSDimitry Andric   if (lastLineEnd != 0) {
46668d75effSDimitry Andric     __sanitizer_log_write(line, lastLineEnd);
46768d75effSDimitry Andric     internal_memmove(line, line + lastLineEnd, cur - lastLineEnd);
46868d75effSDimitry Andric     cur = cur - lastLineEnd;
46968d75effSDimitry Andric     lastLineEnd = 0;
47068d75effSDimitry Andric   }
47168d75effSDimitry Andric }
47268d75effSDimitry Andric 
47368d75effSDimitry Andric void CatastrophicErrorWrite(const char *buffer, uptr length) {
47468d75effSDimitry Andric   __sanitizer_log_write(buffer, length);
47568d75effSDimitry Andric }
47668d75effSDimitry Andric 
47768d75effSDimitry Andric char **StoredArgv;
47868d75effSDimitry Andric char **StoredEnviron;
47968d75effSDimitry Andric 
48068d75effSDimitry Andric char **GetArgv() { return StoredArgv; }
48168d75effSDimitry Andric char **GetEnviron() { return StoredEnviron; }
48268d75effSDimitry Andric 
48368d75effSDimitry Andric const char *GetEnv(const char *name) {
48468d75effSDimitry Andric   if (StoredEnviron) {
48568d75effSDimitry Andric     uptr NameLen = internal_strlen(name);
48668d75effSDimitry Andric     for (char **Env = StoredEnviron; *Env != 0; Env++) {
48768d75effSDimitry Andric       if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=')
48868d75effSDimitry Andric         return (*Env) + NameLen + 1;
48968d75effSDimitry Andric     }
49068d75effSDimitry Andric   }
49168d75effSDimitry Andric   return nullptr;
49268d75effSDimitry Andric }
49368d75effSDimitry Andric 
49468d75effSDimitry Andric uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) {
49568d75effSDimitry Andric   const char *argv0 = "<UNKNOWN>";
49668d75effSDimitry Andric   if (StoredArgv && StoredArgv[0]) {
49768d75effSDimitry Andric     argv0 = StoredArgv[0];
49868d75effSDimitry Andric   }
49968d75effSDimitry Andric   internal_strncpy(buf, argv0, buf_len);
50068d75effSDimitry Andric   return internal_strlen(buf);
50168d75effSDimitry Andric }
50268d75effSDimitry Andric 
50368d75effSDimitry Andric uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
50468d75effSDimitry Andric   return ReadBinaryName(buf, buf_len);
50568d75effSDimitry Andric }
50668d75effSDimitry Andric 
50768d75effSDimitry Andric uptr MainThreadStackBase, MainThreadStackSize;
50868d75effSDimitry Andric 
50968d75effSDimitry Andric bool GetRandom(void *buffer, uptr length, bool blocking) {
51068d75effSDimitry Andric   CHECK_LE(length, ZX_CPRNG_DRAW_MAX_LEN);
51168d75effSDimitry Andric   _zx_cprng_draw(buffer, length);
51268d75effSDimitry Andric   return true;
51368d75effSDimitry Andric }
51468d75effSDimitry Andric 
515*fe6060f1SDimitry Andric u32 GetNumberOfCPUs() { return zx_system_get_num_cpus(); }
51668d75effSDimitry Andric 
51768d75effSDimitry Andric uptr GetRSS() { UNIMPLEMENTED(); }
51868d75effSDimitry Andric 
519e8d8bef9SDimitry Andric void InitializePlatformCommonFlags(CommonFlags *cf) {}
520e8d8bef9SDimitry Andric 
52168d75effSDimitry Andric }  // namespace __sanitizer
52268d75effSDimitry Andric 
52368d75effSDimitry Andric using namespace __sanitizer;
52468d75effSDimitry Andric 
52568d75effSDimitry Andric extern "C" {
52668d75effSDimitry Andric void __sanitizer_startup_hook(int argc, char **argv, char **envp,
52768d75effSDimitry Andric                               void *stack_base, size_t stack_size) {
52868d75effSDimitry Andric   __sanitizer::StoredArgv = argv;
52968d75effSDimitry Andric   __sanitizer::StoredEnviron = envp;
53068d75effSDimitry Andric   __sanitizer::MainThreadStackBase = reinterpret_cast<uintptr_t>(stack_base);
53168d75effSDimitry Andric   __sanitizer::MainThreadStackSize = stack_size;
53268d75effSDimitry Andric }
53368d75effSDimitry Andric 
53468d75effSDimitry Andric void __sanitizer_set_report_path(const char *path) {
53568d75effSDimitry Andric   // Handle the initialization code in each sanitizer, but no other calls.
53668d75effSDimitry Andric   // This setting is never consulted on Fuchsia.
53768d75effSDimitry Andric   DCHECK_EQ(path, common_flags()->log_path);
53868d75effSDimitry Andric }
53968d75effSDimitry Andric 
54068d75effSDimitry Andric void __sanitizer_set_report_fd(void *fd) {
54168d75effSDimitry Andric   UNREACHABLE("not available on Fuchsia");
54268d75effSDimitry Andric }
543e8d8bef9SDimitry Andric 
544e8d8bef9SDimitry Andric const char *__sanitizer_get_report_path() {
545e8d8bef9SDimitry Andric   UNREACHABLE("not available on Fuchsia");
546e8d8bef9SDimitry Andric }
54768d75effSDimitry Andric }  // extern "C"
54868d75effSDimitry Andric 
54968d75effSDimitry Andric #endif  // SANITIZER_FUCHSIA
550