xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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"
2681ad6265SDimitry Andric #  include "sanitizer_interface_internal.h"
27e8d8bef9SDimitry Andric #  include "sanitizer_libc.h"
28e8d8bef9SDimitry Andric #  include "sanitizer_mutex.h"
2968d75effSDimitry Andric 
3068d75effSDimitry Andric namespace __sanitizer {
3168d75effSDimitry Andric 
3268d75effSDimitry Andric void NORETURN internal__exit(int exitcode) { _zx_process_exit(exitcode); }
3368d75effSDimitry Andric 
3468d75effSDimitry Andric uptr internal_sched_yield() {
3581ad6265SDimitry Andric   zx_status_t status = _zx_thread_legacy_yield(0u);
3668d75effSDimitry Andric   CHECK_EQ(status, ZX_OK);
3768d75effSDimitry Andric   return 0;  // Why doesn't this return void?
3868d75effSDimitry Andric }
3968d75effSDimitry Andric 
40fe6060f1SDimitry Andric void internal_usleep(u64 useconds) {
41fe6060f1SDimitry Andric   zx_status_t status = _zx_nanosleep(_zx_deadline_after(ZX_USEC(useconds)));
4268d75effSDimitry Andric   CHECK_EQ(status, ZX_OK);
4368d75effSDimitry Andric }
4468d75effSDimitry Andric 
4568d75effSDimitry Andric u64 NanoTime() {
46e8d8bef9SDimitry Andric   zx_handle_t utc_clock = _zx_utc_reference_get();
47e8d8bef9SDimitry Andric   CHECK_NE(utc_clock, ZX_HANDLE_INVALID);
4868d75effSDimitry Andric   zx_time_t time;
49e8d8bef9SDimitry Andric   zx_status_t status = _zx_clock_read(utc_clock, &time);
5068d75effSDimitry Andric   CHECK_EQ(status, ZX_OK);
5168d75effSDimitry Andric   return time;
5268d75effSDimitry Andric }
5368d75effSDimitry Andric 
5468d75effSDimitry Andric u64 MonotonicNanoTime() { return _zx_clock_get_monotonic(); }
5568d75effSDimitry Andric 
5668d75effSDimitry Andric uptr internal_getpid() {
5768d75effSDimitry Andric   zx_info_handle_basic_t info;
5868d75effSDimitry Andric   zx_status_t status =
5968d75effSDimitry Andric       _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &info,
6068d75effSDimitry Andric                           sizeof(info), NULL, NULL);
6168d75effSDimitry Andric   CHECK_EQ(status, ZX_OK);
6268d75effSDimitry Andric   uptr pid = static_cast<uptr>(info.koid);
6368d75effSDimitry Andric   CHECK_EQ(pid, info.koid);
6468d75effSDimitry Andric   return pid;
6568d75effSDimitry Andric }
6668d75effSDimitry Andric 
67fe6060f1SDimitry Andric int internal_dlinfo(void *handle, int request, void *p) { UNIMPLEMENTED(); }
685ffd83dbSDimitry Andric 
6968d75effSDimitry Andric uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); }
7068d75effSDimitry Andric 
7168d75effSDimitry Andric tid_t GetTid() { return GetThreadSelf(); }
7268d75effSDimitry Andric 
7368d75effSDimitry Andric void Abort() { abort(); }
7468d75effSDimitry Andric 
7568d75effSDimitry Andric int Atexit(void (*function)(void)) { return atexit(function); }
7668d75effSDimitry Andric 
7768d75effSDimitry Andric void GetThreadStackTopAndBottom(bool, uptr *stack_top, uptr *stack_bottom) {
7868d75effSDimitry Andric   pthread_attr_t attr;
7968d75effSDimitry Andric   CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
8068d75effSDimitry Andric   void *base;
8168d75effSDimitry Andric   size_t size;
8268d75effSDimitry Andric   CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0);
8368d75effSDimitry Andric   CHECK_EQ(pthread_attr_destroy(&attr), 0);
8468d75effSDimitry Andric 
8568d75effSDimitry Andric   *stack_bottom = reinterpret_cast<uptr>(base);
8668d75effSDimitry Andric   *stack_top = *stack_bottom + size;
8768d75effSDimitry Andric }
8868d75effSDimitry Andric 
8968d75effSDimitry Andric void InitializePlatformEarly() {}
9068d75effSDimitry Andric void CheckASLR() {}
9168d75effSDimitry Andric void CheckMPROTECT() {}
9281ad6265SDimitry Andric void PlatformPrepareForSandboxing(void *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 
103fe6060f1SDimitry Andric void FutexWait(atomic_uint32_t *p, u32 cmp) {
104fe6060f1SDimitry Andric   zx_status_t status = _zx_futex_wait(reinterpret_cast<zx_futex_t *>(p), cmp,
105fe6060f1SDimitry Andric                                       ZX_HANDLE_INVALID, ZX_TIME_INFINITE);
106fe6060f1SDimitry Andric   if (status != ZX_ERR_BAD_STATE)  // Normal race.
107fe6060f1SDimitry Andric     CHECK_EQ(status, ZX_OK);
108fe6060f1SDimitry Andric }
109fe6060f1SDimitry Andric 
110fe6060f1SDimitry Andric void FutexWake(atomic_uint32_t *p, u32 count) {
111fe6060f1SDimitry Andric   zx_status_t status = _zx_futex_wake(reinterpret_cast<zx_futex_t *>(p), count);
112fe6060f1SDimitry Andric   CHECK_EQ(status, ZX_OK);
113fe6060f1SDimitry Andric }
114fe6060f1SDimitry Andric 
115fe6060f1SDimitry Andric uptr GetPageSize() { return _zx_system_get_page_size(); }
11668d75effSDimitry Andric 
117fe6060f1SDimitry Andric uptr GetMmapGranularity() { return _zx_system_get_page_size(); }
11868d75effSDimitry Andric 
11968d75effSDimitry Andric sanitizer_shadow_bounds_t ShadowBounds;
12068d75effSDimitry Andric 
121fe6060f1SDimitry Andric void InitShadowBounds() { ShadowBounds = __sanitizer_shadow_bounds(); }
122fe6060f1SDimitry Andric 
12368d75effSDimitry Andric uptr GetMaxUserVirtualAddress() {
124fe6060f1SDimitry Andric   InitShadowBounds();
12568d75effSDimitry Andric   return ShadowBounds.memory_limit - 1;
12668d75effSDimitry Andric }
12768d75effSDimitry Andric 
12868d75effSDimitry Andric uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); }
12968d75effSDimitry Andric 
13081ad6265SDimitry Andric bool ErrorIsOOM(error_t err) { return err == ZX_ERR_NO_MEMORY; }
13181ad6265SDimitry Andric 
1327a6dacacSDimitry Andric // For any sanitizer internal that needs to map something which can be unmapped
1337a6dacacSDimitry Andric // later, first attempt to map to a pre-allocated VMAR. This helps reduce
1347a6dacacSDimitry Andric // fragmentation from many small anonymous mmap calls. A good value for this
1357a6dacacSDimitry Andric // VMAR size would be the total size of your typical sanitizer internal objects
1367a6dacacSDimitry Andric // allocated in an "average" process lifetime. Examples of this include:
1377a6dacacSDimitry Andric // FakeStack, LowLevelAllocator mappings, TwoLevelMap, InternalMmapVector,
1387a6dacacSDimitry Andric // StackStore, CreateAsanThread, etc.
1397a6dacacSDimitry Andric //
1407a6dacacSDimitry Andric // This is roughly equal to the total sum of sanitizer internal mappings for a
1417a6dacacSDimitry Andric // large test case.
1427a6dacacSDimitry Andric constexpr size_t kSanitizerHeapVmarSize = 13ULL << 20;
1437a6dacacSDimitry Andric static zx_handle_t gSanitizerHeapVmar = ZX_HANDLE_INVALID;
1447a6dacacSDimitry Andric 
1457a6dacacSDimitry Andric static zx_status_t GetSanitizerHeapVmar(zx_handle_t *vmar) {
1467a6dacacSDimitry Andric   zx_status_t status = ZX_OK;
1477a6dacacSDimitry Andric   if (gSanitizerHeapVmar == ZX_HANDLE_INVALID) {
1487a6dacacSDimitry Andric     CHECK_EQ(kSanitizerHeapVmarSize % GetPageSizeCached(), 0);
1497a6dacacSDimitry Andric     uintptr_t base;
1507a6dacacSDimitry Andric     status = _zx_vmar_allocate(
1517a6dacacSDimitry Andric         _zx_vmar_root_self(),
1527a6dacacSDimitry Andric         ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0,
1537a6dacacSDimitry Andric         kSanitizerHeapVmarSize, &gSanitizerHeapVmar, &base);
1547a6dacacSDimitry Andric   }
1557a6dacacSDimitry Andric   *vmar = gSanitizerHeapVmar;
1567a6dacacSDimitry Andric   if (status == ZX_OK)
1577a6dacacSDimitry Andric     CHECK_NE(gSanitizerHeapVmar, ZX_HANDLE_INVALID);
1587a6dacacSDimitry Andric   return status;
1597a6dacacSDimitry Andric }
1607a6dacacSDimitry Andric 
1617a6dacacSDimitry Andric static zx_status_t TryVmoMapSanitizerVmar(zx_vm_option_t options,
1627a6dacacSDimitry Andric                                           size_t vmar_offset, zx_handle_t vmo,
1637a6dacacSDimitry Andric                                           size_t size, uintptr_t *addr,
1647a6dacacSDimitry Andric                                           zx_handle_t *vmar_used = nullptr) {
1657a6dacacSDimitry Andric   zx_handle_t vmar;
1667a6dacacSDimitry Andric   zx_status_t status = GetSanitizerHeapVmar(&vmar);
1677a6dacacSDimitry Andric   if (status != ZX_OK)
1687a6dacacSDimitry Andric     return status;
1697a6dacacSDimitry Andric 
1707a6dacacSDimitry Andric   status = _zx_vmar_map(gSanitizerHeapVmar, options, vmar_offset, vmo,
1717a6dacacSDimitry Andric                         /*vmo_offset=*/0, size, addr);
1727a6dacacSDimitry Andric   if (vmar_used)
1737a6dacacSDimitry Andric     *vmar_used = gSanitizerHeapVmar;
1747a6dacacSDimitry Andric   if (status == ZX_ERR_NO_RESOURCES || status == ZX_ERR_INVALID_ARGS) {
1757a6dacacSDimitry Andric     // This means there's no space in the heap VMAR, so fallback to the root
1767a6dacacSDimitry Andric     // VMAR.
1777a6dacacSDimitry Andric     status = _zx_vmar_map(_zx_vmar_root_self(), options, vmar_offset, vmo,
1787a6dacacSDimitry Andric                           /*vmo_offset=*/0, size, addr);
1797a6dacacSDimitry Andric     if (vmar_used)
1807a6dacacSDimitry Andric       *vmar_used = _zx_vmar_root_self();
1817a6dacacSDimitry Andric   }
1827a6dacacSDimitry Andric 
1837a6dacacSDimitry Andric   return status;
1847a6dacacSDimitry Andric }
1857a6dacacSDimitry Andric 
18668d75effSDimitry Andric static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type,
18768d75effSDimitry Andric                                   bool raw_report, bool die_for_nomem) {
188fe6060f1SDimitry Andric   size = RoundUpTo(size, GetPageSize());
18968d75effSDimitry Andric 
19068d75effSDimitry Andric   zx_handle_t vmo;
19168d75effSDimitry Andric   zx_status_t status = _zx_vmo_create(size, 0, &vmo);
19268d75effSDimitry Andric   if (status != ZX_OK) {
19368d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY || die_for_nomem)
19468d75effSDimitry Andric       ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status,
19568d75effSDimitry Andric                               raw_report);
19668d75effSDimitry Andric     return nullptr;
19768d75effSDimitry Andric   }
19868d75effSDimitry Andric   _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type,
19968d75effSDimitry Andric                           internal_strlen(mem_type));
20068d75effSDimitry Andric 
20168d75effSDimitry Andric   uintptr_t addr;
2027a6dacacSDimitry Andric   status = TryVmoMapSanitizerVmar(ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
2037a6dacacSDimitry Andric                                   /*vmar_offset=*/0, vmo, size, &addr);
20468d75effSDimitry Andric   _zx_handle_close(vmo);
20568d75effSDimitry Andric 
20668d75effSDimitry Andric   if (status != ZX_OK) {
20768d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY || die_for_nomem)
20868d75effSDimitry Andric       ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status,
20968d75effSDimitry Andric                               raw_report);
21068d75effSDimitry Andric     return nullptr;
21168d75effSDimitry Andric   }
21268d75effSDimitry Andric 
21368d75effSDimitry Andric   IncreaseTotalMmap(size);
21468d75effSDimitry Andric 
21568d75effSDimitry Andric   return reinterpret_cast<void *>(addr);
21668d75effSDimitry Andric }
21768d75effSDimitry Andric 
21868d75effSDimitry Andric void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
21968d75effSDimitry Andric   return DoAnonymousMmapOrDie(size, mem_type, raw_report, true);
22068d75effSDimitry Andric }
22168d75effSDimitry Andric 
22268d75effSDimitry Andric void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
22368d75effSDimitry Andric   return MmapOrDie(size, mem_type);
22468d75effSDimitry Andric }
22568d75effSDimitry Andric 
22668d75effSDimitry Andric void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
22768d75effSDimitry Andric   return DoAnonymousMmapOrDie(size, mem_type, false, false);
22868d75effSDimitry Andric }
22968d75effSDimitry Andric 
23068d75effSDimitry Andric uptr ReservedAddressRange::Init(uptr init_size, const char *name,
23168d75effSDimitry Andric                                 uptr fixed_addr) {
232fe6060f1SDimitry Andric   init_size = RoundUpTo(init_size, GetPageSize());
23368d75effSDimitry Andric   DCHECK_EQ(os_handle_, ZX_HANDLE_INVALID);
23468d75effSDimitry Andric   uintptr_t base;
23568d75effSDimitry Andric   zx_handle_t vmar;
236fe6060f1SDimitry Andric   zx_status_t status = _zx_vmar_allocate(
23768d75effSDimitry Andric       _zx_vmar_root_self(),
238fe6060f1SDimitry Andric       ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0,
239fe6060f1SDimitry Andric       init_size, &vmar, &base);
24068d75effSDimitry Andric   if (status != ZX_OK)
24168d75effSDimitry Andric     ReportMmapFailureAndDie(init_size, name, "zx_vmar_allocate", status);
24268d75effSDimitry Andric   base_ = reinterpret_cast<void *>(base);
24368d75effSDimitry Andric   size_ = init_size;
24468d75effSDimitry Andric   name_ = name;
24568d75effSDimitry Andric   os_handle_ = vmar;
24668d75effSDimitry Andric 
24768d75effSDimitry Andric   return reinterpret_cast<uptr>(base_);
24868d75effSDimitry Andric }
24968d75effSDimitry Andric 
25068d75effSDimitry Andric static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size,
25168d75effSDimitry Andric                              void *base, const char *name, bool die_for_nomem) {
25268d75effSDimitry Andric   uptr offset = fixed_addr - reinterpret_cast<uptr>(base);
253fe6060f1SDimitry Andric   map_size = RoundUpTo(map_size, GetPageSize());
25468d75effSDimitry Andric   zx_handle_t vmo;
25568d75effSDimitry Andric   zx_status_t status = _zx_vmo_create(map_size, 0, &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_vmo_create", status);
25968d75effSDimitry Andric     return 0;
26068d75effSDimitry Andric   }
26168d75effSDimitry Andric   _zx_object_set_property(vmo, ZX_PROP_NAME, name, internal_strlen(name));
26268d75effSDimitry Andric   DCHECK_GE(base + size_, map_size + offset);
26368d75effSDimitry Andric   uintptr_t addr;
26468d75effSDimitry Andric 
26568d75effSDimitry Andric   status =
26668d75effSDimitry Andric       _zx_vmar_map(vmar, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC,
26768d75effSDimitry Andric                    offset, vmo, 0, map_size, &addr);
26868d75effSDimitry Andric   _zx_handle_close(vmo);
26968d75effSDimitry Andric   if (status != ZX_OK) {
27068d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY || die_for_nomem) {
27168d75effSDimitry Andric       ReportMmapFailureAndDie(map_size, name, "zx_vmar_map", status);
27268d75effSDimitry Andric     }
27368d75effSDimitry Andric     return 0;
27468d75effSDimitry Andric   }
27568d75effSDimitry Andric   IncreaseTotalMmap(map_size);
27668d75effSDimitry Andric   return addr;
27768d75effSDimitry Andric }
27868d75effSDimitry Andric 
27968d75effSDimitry Andric uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size,
28068d75effSDimitry Andric                                const char *name) {
2815f757f3fSDimitry Andric   return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_,
2825f757f3fSDimitry Andric                           name ? name : name_, false);
28368d75effSDimitry Andric }
28468d75effSDimitry Andric 
28568d75effSDimitry Andric uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr map_size,
28668d75effSDimitry Andric                                     const char *name) {
2875f757f3fSDimitry Andric   return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_,
2885f757f3fSDimitry Andric                           name ? name : name_, true);
28968d75effSDimitry Andric }
29068d75effSDimitry Andric 
291*0fca6ea1SDimitry Andric void UnmapOrDieVmar(void *addr, uptr size, zx_handle_t target_vmar,
292*0fca6ea1SDimitry Andric                     bool raw_report) {
293fe6060f1SDimitry Andric   if (!addr || !size)
294fe6060f1SDimitry Andric     return;
295fe6060f1SDimitry Andric   size = RoundUpTo(size, GetPageSize());
29668d75effSDimitry Andric 
29768d75effSDimitry Andric   zx_status_t status =
29868d75effSDimitry Andric       _zx_vmar_unmap(target_vmar, reinterpret_cast<uintptr_t>(addr), size);
2997a6dacacSDimitry Andric   if (status == ZX_ERR_INVALID_ARGS && target_vmar == gSanitizerHeapVmar) {
3007a6dacacSDimitry Andric     // If there wasn't any space in the heap vmar, the fallback was the root
3017a6dacacSDimitry Andric     // vmar.
3027a6dacacSDimitry Andric     status = _zx_vmar_unmap(_zx_vmar_root_self(),
3037a6dacacSDimitry Andric                             reinterpret_cast<uintptr_t>(addr), size);
3047a6dacacSDimitry Andric   }
305*0fca6ea1SDimitry Andric   if (status != ZX_OK)
306*0fca6ea1SDimitry Andric     ReportMunmapFailureAndDie(addr, size, status, raw_report);
30768d75effSDimitry Andric 
30868d75effSDimitry Andric   DecreaseTotalMmap(size);
30968d75effSDimitry Andric }
31068d75effSDimitry Andric 
31168d75effSDimitry Andric void ReservedAddressRange::Unmap(uptr addr, uptr size) {
31268d75effSDimitry Andric   CHECK_LE(size, size_);
31368d75effSDimitry Andric   const zx_handle_t vmar = static_cast<zx_handle_t>(os_handle_);
31468d75effSDimitry Andric   if (addr == reinterpret_cast<uptr>(base_)) {
31568d75effSDimitry Andric     if (size == size_) {
31668d75effSDimitry Andric       // Destroying the vmar effectively unmaps the whole mapping.
31768d75effSDimitry Andric       _zx_vmar_destroy(vmar);
31868d75effSDimitry Andric       _zx_handle_close(vmar);
31968d75effSDimitry Andric       os_handle_ = static_cast<uptr>(ZX_HANDLE_INVALID);
32068d75effSDimitry Andric       DecreaseTotalMmap(size);
32168d75effSDimitry Andric       return;
32268d75effSDimitry Andric     }
32368d75effSDimitry Andric   } else {
32468d75effSDimitry Andric     CHECK_EQ(addr + size, reinterpret_cast<uptr>(base_) + size_);
32568d75effSDimitry Andric   }
32668d75effSDimitry Andric   // Partial unmapping does not affect the fact that the initial range is still
32768d75effSDimitry Andric   // reserved, and the resulting unmapped memory can't be reused.
328*0fca6ea1SDimitry Andric   UnmapOrDieVmar(reinterpret_cast<void *>(addr), size, vmar,
329*0fca6ea1SDimitry Andric                  /*raw_report=*/false);
33068d75effSDimitry Andric }
33168d75effSDimitry Andric 
33268d75effSDimitry Andric // This should never be called.
33368d75effSDimitry Andric void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {
33468d75effSDimitry Andric   UNIMPLEMENTED();
33568d75effSDimitry Andric }
33668d75effSDimitry Andric 
3374824e7fdSDimitry Andric bool MprotectNoAccess(uptr addr, uptr size) {
3380eae32dcSDimitry Andric   return _zx_vmar_protect(_zx_vmar_root_self(), 0, addr, size) == ZX_OK;
3394824e7fdSDimitry Andric }
3404824e7fdSDimitry Andric 
3414824e7fdSDimitry Andric bool MprotectReadOnly(uptr addr, uptr size) {
3420eae32dcSDimitry Andric   return _zx_vmar_protect(_zx_vmar_root_self(), ZX_VM_PERM_READ, addr, size) ==
3434824e7fdSDimitry Andric          ZX_OK;
3444824e7fdSDimitry Andric }
3454824e7fdSDimitry Andric 
34606c3fb27SDimitry Andric bool MprotectReadWrite(uptr addr, uptr size) {
34706c3fb27SDimitry Andric   return _zx_vmar_protect(_zx_vmar_root_self(),
34806c3fb27SDimitry Andric                           ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, addr,
34906c3fb27SDimitry Andric                           size) == ZX_OK;
35006c3fb27SDimitry Andric }
35106c3fb27SDimitry Andric 
35268d75effSDimitry Andric void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
35368d75effSDimitry Andric                                    const char *mem_type) {
354fe6060f1SDimitry Andric   CHECK_GE(size, GetPageSize());
35568d75effSDimitry Andric   CHECK(IsPowerOfTwo(size));
35668d75effSDimitry Andric   CHECK(IsPowerOfTwo(alignment));
35768d75effSDimitry Andric 
35868d75effSDimitry Andric   zx_handle_t vmo;
35968d75effSDimitry Andric   zx_status_t status = _zx_vmo_create(size, 0, &vmo);
36068d75effSDimitry Andric   if (status != ZX_OK) {
36168d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY)
36268d75effSDimitry Andric       ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status, false);
36368d75effSDimitry Andric     return nullptr;
36468d75effSDimitry Andric   }
36568d75effSDimitry Andric   _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type,
36668d75effSDimitry Andric                           internal_strlen(mem_type));
36768d75effSDimitry Andric 
36868d75effSDimitry Andric   // Map a larger size to get a chunk of address space big enough that
36968d75effSDimitry Andric   // it surely contains an aligned region of the requested size.  Then
37068d75effSDimitry Andric   // overwrite the aligned middle portion with a mapping from the
37168d75effSDimitry Andric   // beginning of the VMO, and unmap the excess before and after.
37268d75effSDimitry Andric   size_t map_size = size + alignment;
37368d75effSDimitry Andric   uintptr_t addr;
3747a6dacacSDimitry Andric   zx_handle_t vmar_used;
3757a6dacacSDimitry Andric   status = TryVmoMapSanitizerVmar(ZX_VM_PERM_READ | ZX_VM_PERM_WRITE,
3767a6dacacSDimitry Andric                                   /*vmar_offset=*/0, vmo, map_size, &addr,
3777a6dacacSDimitry Andric                                   &vmar_used);
37868d75effSDimitry Andric   if (status == ZX_OK) {
37968d75effSDimitry Andric     uintptr_t map_addr = addr;
38068d75effSDimitry Andric     uintptr_t map_end = map_addr + map_size;
38168d75effSDimitry Andric     addr = RoundUpTo(map_addr, alignment);
38268d75effSDimitry Andric     uintptr_t end = addr + size;
38368d75effSDimitry Andric     if (addr != map_addr) {
38468d75effSDimitry Andric       zx_info_vmar_t info;
3857a6dacacSDimitry Andric       status = _zx_object_get_info(vmar_used, ZX_INFO_VMAR, &info, sizeof(info),
3867a6dacacSDimitry Andric                                    NULL, NULL);
38768d75effSDimitry Andric       if (status == ZX_OK) {
38868d75effSDimitry Andric         uintptr_t new_addr;
38968d75effSDimitry Andric         status = _zx_vmar_map(
3907a6dacacSDimitry Andric             vmar_used,
39168d75effSDimitry Andric             ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC_OVERWRITE,
39268d75effSDimitry Andric             addr - info.base, vmo, 0, size, &new_addr);
393fe6060f1SDimitry Andric         if (status == ZX_OK)
394fe6060f1SDimitry Andric           CHECK_EQ(new_addr, addr);
39568d75effSDimitry Andric       }
39668d75effSDimitry Andric     }
39768d75effSDimitry Andric     if (status == ZX_OK && addr != map_addr)
3987a6dacacSDimitry Andric       status = _zx_vmar_unmap(vmar_used, map_addr, addr - map_addr);
39968d75effSDimitry Andric     if (status == ZX_OK && end != map_end)
4007a6dacacSDimitry Andric       status = _zx_vmar_unmap(vmar_used, end, map_end - end);
40168d75effSDimitry Andric   }
40268d75effSDimitry Andric   _zx_handle_close(vmo);
40368d75effSDimitry Andric 
40468d75effSDimitry Andric   if (status != ZX_OK) {
40568d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY)
40668d75effSDimitry Andric       ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status, false);
40768d75effSDimitry Andric     return nullptr;
40868d75effSDimitry Andric   }
40968d75effSDimitry Andric 
41068d75effSDimitry Andric   IncreaseTotalMmap(size);
41168d75effSDimitry Andric 
41268d75effSDimitry Andric   return reinterpret_cast<void *>(addr);
41368d75effSDimitry Andric }
41468d75effSDimitry Andric 
415*0fca6ea1SDimitry Andric void UnmapOrDie(void *addr, uptr size, bool raw_report) {
416*0fca6ea1SDimitry Andric   UnmapOrDieVmar(addr, size, gSanitizerHeapVmar, raw_report);
41768d75effSDimitry Andric }
41868d75effSDimitry Andric 
419fe6060f1SDimitry Andric void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
420fe6060f1SDimitry Andric   uptr beg_aligned = RoundUpTo(beg, GetPageSize());
421fe6060f1SDimitry Andric   uptr end_aligned = RoundDownTo(end, GetPageSize());
422fe6060f1SDimitry Andric   if (beg_aligned < end_aligned) {
423fe6060f1SDimitry Andric     zx_handle_t root_vmar = _zx_vmar_root_self();
424fe6060f1SDimitry Andric     CHECK_NE(root_vmar, ZX_HANDLE_INVALID);
425fe6060f1SDimitry Andric     zx_status_t status =
426fe6060f1SDimitry Andric         _zx_vmar_op_range(root_vmar, ZX_VMAR_OP_DECOMMIT, beg_aligned,
427fe6060f1SDimitry Andric                           end_aligned - beg_aligned, nullptr, 0);
428fe6060f1SDimitry Andric     CHECK_EQ(status, ZX_OK);
429fe6060f1SDimitry Andric   }
430fe6060f1SDimitry Andric }
43168d75effSDimitry Andric 
43268d75effSDimitry Andric void DumpProcessMap() {
43368d75effSDimitry Andric   // TODO(mcgrathr): write it
43468d75effSDimitry Andric   return;
43568d75effSDimitry Andric }
43668d75effSDimitry Andric 
43768d75effSDimitry Andric bool IsAccessibleMemoryRange(uptr beg, uptr size) {
43868d75effSDimitry Andric   // TODO(mcgrathr): Figure out a better way.
43968d75effSDimitry Andric   zx_handle_t vmo;
44068d75effSDimitry Andric   zx_status_t status = _zx_vmo_create(size, 0, &vmo);
44168d75effSDimitry Andric   if (status == ZX_OK) {
44268d75effSDimitry Andric     status = _zx_vmo_write(vmo, reinterpret_cast<const void *>(beg), 0, size);
44368d75effSDimitry Andric     _zx_handle_close(vmo);
44468d75effSDimitry Andric   }
44568d75effSDimitry Andric   return status == ZX_OK;
44668d75effSDimitry Andric }
44768d75effSDimitry Andric 
44868d75effSDimitry Andric // FIXME implement on this platform.
449349cc55cSDimitry Andric void GetMemoryProfile(fill_profile_f cb, uptr *stats) {}
45068d75effSDimitry Andric 
45168d75effSDimitry Andric bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
45268d75effSDimitry Andric                       uptr *read_len, uptr max_len, error_t *errno_p) {
45381ad6265SDimitry Andric   *errno_p = ZX_ERR_NOT_SUPPORTED;
45481ad6265SDimitry Andric   return false;
45568d75effSDimitry Andric }
45668d75effSDimitry Andric 
45768d75effSDimitry Andric void RawWrite(const char *buffer) {
45868d75effSDimitry Andric   constexpr size_t size = 128;
45968d75effSDimitry Andric   static _Thread_local char line[size];
46068d75effSDimitry Andric   static _Thread_local size_t lastLineEnd = 0;
46168d75effSDimitry Andric   static _Thread_local size_t cur = 0;
46268d75effSDimitry Andric 
46368d75effSDimitry Andric   while (*buffer) {
46468d75effSDimitry Andric     if (cur >= size) {
46568d75effSDimitry Andric       if (lastLineEnd == 0)
46668d75effSDimitry Andric         lastLineEnd = size;
46768d75effSDimitry Andric       __sanitizer_log_write(line, lastLineEnd);
46868d75effSDimitry Andric       internal_memmove(line, line + lastLineEnd, cur - lastLineEnd);
46968d75effSDimitry Andric       cur = cur - lastLineEnd;
47068d75effSDimitry Andric       lastLineEnd = 0;
47168d75effSDimitry Andric     }
47268d75effSDimitry Andric     if (*buffer == '\n')
47368d75effSDimitry Andric       lastLineEnd = cur + 1;
47468d75effSDimitry Andric     line[cur++] = *buffer++;
47568d75effSDimitry Andric   }
47668d75effSDimitry Andric   // Flush all complete lines before returning.
47768d75effSDimitry Andric   if (lastLineEnd != 0) {
47868d75effSDimitry Andric     __sanitizer_log_write(line, lastLineEnd);
47968d75effSDimitry Andric     internal_memmove(line, line + lastLineEnd, cur - lastLineEnd);
48068d75effSDimitry Andric     cur = cur - lastLineEnd;
48168d75effSDimitry Andric     lastLineEnd = 0;
48268d75effSDimitry Andric   }
48368d75effSDimitry Andric }
48468d75effSDimitry Andric 
48568d75effSDimitry Andric void CatastrophicErrorWrite(const char *buffer, uptr length) {
48668d75effSDimitry Andric   __sanitizer_log_write(buffer, length);
48768d75effSDimitry Andric }
48868d75effSDimitry Andric 
48968d75effSDimitry Andric char **StoredArgv;
49068d75effSDimitry Andric char **StoredEnviron;
49168d75effSDimitry Andric 
49268d75effSDimitry Andric char **GetArgv() { return StoredArgv; }
49368d75effSDimitry Andric char **GetEnviron() { return StoredEnviron; }
49468d75effSDimitry Andric 
49568d75effSDimitry Andric const char *GetEnv(const char *name) {
49668d75effSDimitry Andric   if (StoredEnviron) {
49768d75effSDimitry Andric     uptr NameLen = internal_strlen(name);
49868d75effSDimitry Andric     for (char **Env = StoredEnviron; *Env != 0; Env++) {
49968d75effSDimitry Andric       if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=')
50068d75effSDimitry Andric         return (*Env) + NameLen + 1;
50168d75effSDimitry Andric     }
50268d75effSDimitry Andric   }
50368d75effSDimitry Andric   return nullptr;
50468d75effSDimitry Andric }
50568d75effSDimitry Andric 
50668d75effSDimitry Andric uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) {
50768d75effSDimitry Andric   const char *argv0 = "<UNKNOWN>";
50868d75effSDimitry Andric   if (StoredArgv && StoredArgv[0]) {
50968d75effSDimitry Andric     argv0 = StoredArgv[0];
51068d75effSDimitry Andric   }
51168d75effSDimitry Andric   internal_strncpy(buf, argv0, buf_len);
51268d75effSDimitry Andric   return internal_strlen(buf);
51368d75effSDimitry Andric }
51468d75effSDimitry Andric 
51568d75effSDimitry Andric uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
51668d75effSDimitry Andric   return ReadBinaryName(buf, buf_len);
51768d75effSDimitry Andric }
51868d75effSDimitry Andric 
51968d75effSDimitry Andric uptr MainThreadStackBase, MainThreadStackSize;
52068d75effSDimitry Andric 
52168d75effSDimitry Andric bool GetRandom(void *buffer, uptr length, bool blocking) {
52268d75effSDimitry Andric   CHECK_LE(length, ZX_CPRNG_DRAW_MAX_LEN);
52368d75effSDimitry Andric   _zx_cprng_draw(buffer, length);
52468d75effSDimitry Andric   return true;
52568d75effSDimitry Andric }
52668d75effSDimitry Andric 
527fe6060f1SDimitry Andric u32 GetNumberOfCPUs() { return zx_system_get_num_cpus(); }
52868d75effSDimitry Andric 
52968d75effSDimitry Andric uptr GetRSS() { UNIMPLEMENTED(); }
53068d75effSDimitry Andric 
5310eae32dcSDimitry Andric void *internal_start_thread(void *(*func)(void *arg), void *arg) { return 0; }
5320eae32dcSDimitry Andric void internal_join_thread(void *th) {}
5330eae32dcSDimitry Andric 
534e8d8bef9SDimitry Andric void InitializePlatformCommonFlags(CommonFlags *cf) {}
535e8d8bef9SDimitry Andric 
53668d75effSDimitry Andric }  // namespace __sanitizer
53768d75effSDimitry Andric 
53868d75effSDimitry Andric using namespace __sanitizer;
53968d75effSDimitry Andric 
54068d75effSDimitry Andric extern "C" {
54168d75effSDimitry Andric void __sanitizer_startup_hook(int argc, char **argv, char **envp,
54268d75effSDimitry Andric                               void *stack_base, size_t stack_size) {
54368d75effSDimitry Andric   __sanitizer::StoredArgv = argv;
54468d75effSDimitry Andric   __sanitizer::StoredEnviron = envp;
54568d75effSDimitry Andric   __sanitizer::MainThreadStackBase = reinterpret_cast<uintptr_t>(stack_base);
54668d75effSDimitry Andric   __sanitizer::MainThreadStackSize = stack_size;
54768d75effSDimitry Andric }
54868d75effSDimitry Andric 
54968d75effSDimitry Andric void __sanitizer_set_report_path(const char *path) {
55068d75effSDimitry Andric   // Handle the initialization code in each sanitizer, but no other calls.
55168d75effSDimitry Andric   // This setting is never consulted on Fuchsia.
55268d75effSDimitry Andric   DCHECK_EQ(path, common_flags()->log_path);
55368d75effSDimitry Andric }
55468d75effSDimitry Andric 
55568d75effSDimitry Andric void __sanitizer_set_report_fd(void *fd) {
55668d75effSDimitry Andric   UNREACHABLE("not available on Fuchsia");
55768d75effSDimitry Andric }
558e8d8bef9SDimitry Andric 
559e8d8bef9SDimitry Andric const char *__sanitizer_get_report_path() {
560e8d8bef9SDimitry Andric   UNREACHABLE("not available on Fuchsia");
561e8d8bef9SDimitry Andric }
56268d75effSDimitry Andric }  // extern "C"
56368d75effSDimitry Andric 
56468d75effSDimitry Andric #endif  // SANITIZER_FUCHSIA
565