xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/sanitizer_common/sanitizer_fuchsia.cpp (revision 4824e7fd18a1223177218d4aec1b3c6c5c4a444e)
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 
39fe6060f1SDimitry Andric void internal_usleep(u64 useconds) {
40fe6060f1SDimitry 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 
66fe6060f1SDimitry 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 
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 
13068d75effSDimitry Andric static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type,
13168d75effSDimitry Andric                                   bool raw_report, bool die_for_nomem) {
132fe6060f1SDimitry Andric   size = RoundUpTo(size, GetPageSize());
13368d75effSDimitry Andric 
13468d75effSDimitry Andric   zx_handle_t vmo;
13568d75effSDimitry Andric   zx_status_t status = _zx_vmo_create(size, 0, &vmo);
13668d75effSDimitry Andric   if (status != ZX_OK) {
13768d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY || die_for_nomem)
13868d75effSDimitry Andric       ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status,
13968d75effSDimitry Andric                               raw_report);
14068d75effSDimitry Andric     return nullptr;
14168d75effSDimitry Andric   }
14268d75effSDimitry Andric   _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type,
14368d75effSDimitry Andric                           internal_strlen(mem_type));
14468d75effSDimitry Andric 
14568d75effSDimitry Andric   // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that?
14668d75effSDimitry Andric   uintptr_t addr;
14768d75effSDimitry Andric   status =
14868d75effSDimitry Andric       _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0,
14968d75effSDimitry Andric                    vmo, 0, size, &addr);
15068d75effSDimitry Andric   _zx_handle_close(vmo);
15168d75effSDimitry Andric 
15268d75effSDimitry Andric   if (status != ZX_OK) {
15368d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY || die_for_nomem)
15468d75effSDimitry Andric       ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status,
15568d75effSDimitry Andric                               raw_report);
15668d75effSDimitry Andric     return nullptr;
15768d75effSDimitry Andric   }
15868d75effSDimitry Andric 
15968d75effSDimitry Andric   IncreaseTotalMmap(size);
16068d75effSDimitry Andric 
16168d75effSDimitry Andric   return reinterpret_cast<void *>(addr);
16268d75effSDimitry Andric }
16368d75effSDimitry Andric 
16468d75effSDimitry Andric void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
16568d75effSDimitry Andric   return DoAnonymousMmapOrDie(size, mem_type, raw_report, true);
16668d75effSDimitry Andric }
16768d75effSDimitry Andric 
16868d75effSDimitry Andric void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
16968d75effSDimitry Andric   return MmapOrDie(size, mem_type);
17068d75effSDimitry Andric }
17168d75effSDimitry Andric 
17268d75effSDimitry Andric void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
17368d75effSDimitry Andric   return DoAnonymousMmapOrDie(size, mem_type, false, false);
17468d75effSDimitry Andric }
17568d75effSDimitry Andric 
17668d75effSDimitry Andric uptr ReservedAddressRange::Init(uptr init_size, const char *name,
17768d75effSDimitry Andric                                 uptr fixed_addr) {
178fe6060f1SDimitry Andric   init_size = RoundUpTo(init_size, GetPageSize());
17968d75effSDimitry Andric   DCHECK_EQ(os_handle_, ZX_HANDLE_INVALID);
18068d75effSDimitry Andric   uintptr_t base;
18168d75effSDimitry Andric   zx_handle_t vmar;
182fe6060f1SDimitry Andric   zx_status_t status = _zx_vmar_allocate(
18368d75effSDimitry Andric       _zx_vmar_root_self(),
184fe6060f1SDimitry Andric       ZX_VM_CAN_MAP_READ | ZX_VM_CAN_MAP_WRITE | ZX_VM_CAN_MAP_SPECIFIC, 0,
185fe6060f1SDimitry Andric       init_size, &vmar, &base);
18668d75effSDimitry Andric   if (status != ZX_OK)
18768d75effSDimitry Andric     ReportMmapFailureAndDie(init_size, name, "zx_vmar_allocate", status);
18868d75effSDimitry Andric   base_ = reinterpret_cast<void *>(base);
18968d75effSDimitry Andric   size_ = init_size;
19068d75effSDimitry Andric   name_ = name;
19168d75effSDimitry Andric   os_handle_ = vmar;
19268d75effSDimitry Andric 
19368d75effSDimitry Andric   return reinterpret_cast<uptr>(base_);
19468d75effSDimitry Andric }
19568d75effSDimitry Andric 
19668d75effSDimitry Andric static uptr DoMmapFixedOrDie(zx_handle_t vmar, uptr fixed_addr, uptr map_size,
19768d75effSDimitry Andric                              void *base, const char *name, bool die_for_nomem) {
19868d75effSDimitry Andric   uptr offset = fixed_addr - reinterpret_cast<uptr>(base);
199fe6060f1SDimitry Andric   map_size = RoundUpTo(map_size, GetPageSize());
20068d75effSDimitry Andric   zx_handle_t vmo;
20168d75effSDimitry Andric   zx_status_t status = _zx_vmo_create(map_size, 0, &vmo);
20268d75effSDimitry Andric   if (status != ZX_OK) {
20368d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY || die_for_nomem)
20468d75effSDimitry Andric       ReportMmapFailureAndDie(map_size, name, "zx_vmo_create", status);
20568d75effSDimitry Andric     return 0;
20668d75effSDimitry Andric   }
20768d75effSDimitry Andric   _zx_object_set_property(vmo, ZX_PROP_NAME, name, internal_strlen(name));
20868d75effSDimitry Andric   DCHECK_GE(base + size_, map_size + offset);
20968d75effSDimitry Andric   uintptr_t addr;
21068d75effSDimitry Andric 
21168d75effSDimitry Andric   status =
21268d75effSDimitry Andric       _zx_vmar_map(vmar, ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC,
21368d75effSDimitry Andric                    offset, vmo, 0, map_size, &addr);
21468d75effSDimitry Andric   _zx_handle_close(vmo);
21568d75effSDimitry Andric   if (status != ZX_OK) {
21668d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY || die_for_nomem) {
21768d75effSDimitry Andric       ReportMmapFailureAndDie(map_size, name, "zx_vmar_map", status);
21868d75effSDimitry Andric     }
21968d75effSDimitry Andric     return 0;
22068d75effSDimitry Andric   }
22168d75effSDimitry Andric   IncreaseTotalMmap(map_size);
22268d75effSDimitry Andric   return addr;
22368d75effSDimitry Andric }
22468d75effSDimitry Andric 
22568d75effSDimitry Andric uptr ReservedAddressRange::Map(uptr fixed_addr, uptr map_size,
22668d75effSDimitry Andric                                const char *name) {
227fe6060f1SDimitry Andric   return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, name_,
228fe6060f1SDimitry Andric                           false);
22968d75effSDimitry Andric }
23068d75effSDimitry Andric 
23168d75effSDimitry Andric uptr ReservedAddressRange::MapOrDie(uptr fixed_addr, uptr map_size,
23268d75effSDimitry Andric                                     const char *name) {
233fe6060f1SDimitry Andric   return DoMmapFixedOrDie(os_handle_, fixed_addr, map_size, base_, name_, true);
23468d75effSDimitry Andric }
23568d75effSDimitry Andric 
23668d75effSDimitry Andric void UnmapOrDieVmar(void *addr, uptr size, zx_handle_t target_vmar) {
237fe6060f1SDimitry Andric   if (!addr || !size)
238fe6060f1SDimitry Andric     return;
239fe6060f1SDimitry Andric   size = RoundUpTo(size, GetPageSize());
24068d75effSDimitry Andric 
24168d75effSDimitry Andric   zx_status_t status =
24268d75effSDimitry Andric       _zx_vmar_unmap(target_vmar, reinterpret_cast<uintptr_t>(addr), size);
24368d75effSDimitry Andric   if (status != ZX_OK) {
24468d75effSDimitry Andric     Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
24568d75effSDimitry Andric            SanitizerToolName, size, size, addr);
24668d75effSDimitry Andric     CHECK("unable to unmap" && 0);
24768d75effSDimitry Andric   }
24868d75effSDimitry Andric 
24968d75effSDimitry Andric   DecreaseTotalMmap(size);
25068d75effSDimitry Andric }
25168d75effSDimitry Andric 
25268d75effSDimitry Andric void ReservedAddressRange::Unmap(uptr addr, uptr size) {
25368d75effSDimitry Andric   CHECK_LE(size, size_);
25468d75effSDimitry Andric   const zx_handle_t vmar = static_cast<zx_handle_t>(os_handle_);
25568d75effSDimitry Andric   if (addr == reinterpret_cast<uptr>(base_)) {
25668d75effSDimitry Andric     if (size == size_) {
25768d75effSDimitry Andric       // Destroying the vmar effectively unmaps the whole mapping.
25868d75effSDimitry Andric       _zx_vmar_destroy(vmar);
25968d75effSDimitry Andric       _zx_handle_close(vmar);
26068d75effSDimitry Andric       os_handle_ = static_cast<uptr>(ZX_HANDLE_INVALID);
26168d75effSDimitry Andric       DecreaseTotalMmap(size);
26268d75effSDimitry Andric       return;
26368d75effSDimitry Andric     }
26468d75effSDimitry Andric   } else {
26568d75effSDimitry Andric     CHECK_EQ(addr + size, reinterpret_cast<uptr>(base_) + size_);
26668d75effSDimitry Andric   }
26768d75effSDimitry Andric   // Partial unmapping does not affect the fact that the initial range is still
26868d75effSDimitry Andric   // reserved, and the resulting unmapped memory can't be reused.
26968d75effSDimitry Andric   UnmapOrDieVmar(reinterpret_cast<void *>(addr), size, vmar);
27068d75effSDimitry Andric }
27168d75effSDimitry Andric 
27268d75effSDimitry Andric // This should never be called.
27368d75effSDimitry Andric void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {
27468d75effSDimitry Andric   UNIMPLEMENTED();
27568d75effSDimitry Andric }
27668d75effSDimitry Andric 
277*4824e7fdSDimitry Andric bool MprotectNoAccess(uptr addr, uptr size) {
278*4824e7fdSDimitry Andric   return _zx_vmar_protect(_zx_vmar_root_self(), 0, Addr, Size) == ZX_OK;
279*4824e7fdSDimitry Andric }
280*4824e7fdSDimitry Andric 
281*4824e7fdSDimitry Andric bool MprotectReadOnly(uptr addr, uptr size) {
282*4824e7fdSDimitry Andric   return _zx_vmar_protect(_zx_vmar_root_self(), ZX_VM_PERM_READ, Addr, Size) ==
283*4824e7fdSDimitry Andric          ZX_OK;
284*4824e7fdSDimitry Andric }
285*4824e7fdSDimitry Andric 
28668d75effSDimitry Andric void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
28768d75effSDimitry Andric                                    const char *mem_type) {
288fe6060f1SDimitry Andric   CHECK_GE(size, GetPageSize());
28968d75effSDimitry Andric   CHECK(IsPowerOfTwo(size));
29068d75effSDimitry Andric   CHECK(IsPowerOfTwo(alignment));
29168d75effSDimitry Andric 
29268d75effSDimitry Andric   zx_handle_t vmo;
29368d75effSDimitry Andric   zx_status_t status = _zx_vmo_create(size, 0, &vmo);
29468d75effSDimitry Andric   if (status != ZX_OK) {
29568d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY)
29668d75effSDimitry Andric       ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status, false);
29768d75effSDimitry Andric     return nullptr;
29868d75effSDimitry Andric   }
29968d75effSDimitry Andric   _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type,
30068d75effSDimitry Andric                           internal_strlen(mem_type));
30168d75effSDimitry Andric 
30268d75effSDimitry Andric   // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that?
30368d75effSDimitry Andric 
30468d75effSDimitry Andric   // Map a larger size to get a chunk of address space big enough that
30568d75effSDimitry Andric   // it surely contains an aligned region of the requested size.  Then
30668d75effSDimitry Andric   // overwrite the aligned middle portion with a mapping from the
30768d75effSDimitry Andric   // beginning of the VMO, and unmap the excess before and after.
30868d75effSDimitry Andric   size_t map_size = size + alignment;
30968d75effSDimitry Andric   uintptr_t addr;
31068d75effSDimitry Andric   status =
31168d75effSDimitry Andric       _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ | ZX_VM_PERM_WRITE, 0,
31268d75effSDimitry Andric                    vmo, 0, map_size, &addr);
31368d75effSDimitry Andric   if (status == ZX_OK) {
31468d75effSDimitry Andric     uintptr_t map_addr = addr;
31568d75effSDimitry Andric     uintptr_t map_end = map_addr + map_size;
31668d75effSDimitry Andric     addr = RoundUpTo(map_addr, alignment);
31768d75effSDimitry Andric     uintptr_t end = addr + size;
31868d75effSDimitry Andric     if (addr != map_addr) {
31968d75effSDimitry Andric       zx_info_vmar_t info;
32068d75effSDimitry Andric       status = _zx_object_get_info(_zx_vmar_root_self(), ZX_INFO_VMAR, &info,
32168d75effSDimitry Andric                                    sizeof(info), NULL, NULL);
32268d75effSDimitry Andric       if (status == ZX_OK) {
32368d75effSDimitry Andric         uintptr_t new_addr;
32468d75effSDimitry Andric         status = _zx_vmar_map(
32568d75effSDimitry Andric             _zx_vmar_root_self(),
32668d75effSDimitry Andric             ZX_VM_PERM_READ | ZX_VM_PERM_WRITE | ZX_VM_SPECIFIC_OVERWRITE,
32768d75effSDimitry Andric             addr - info.base, vmo, 0, size, &new_addr);
328fe6060f1SDimitry Andric         if (status == ZX_OK)
329fe6060f1SDimitry Andric           CHECK_EQ(new_addr, addr);
33068d75effSDimitry Andric       }
33168d75effSDimitry Andric     }
33268d75effSDimitry Andric     if (status == ZX_OK && addr != map_addr)
33368d75effSDimitry Andric       status = _zx_vmar_unmap(_zx_vmar_root_self(), map_addr, addr - map_addr);
33468d75effSDimitry Andric     if (status == ZX_OK && end != map_end)
33568d75effSDimitry Andric       status = _zx_vmar_unmap(_zx_vmar_root_self(), end, map_end - end);
33668d75effSDimitry Andric   }
33768d75effSDimitry Andric   _zx_handle_close(vmo);
33868d75effSDimitry Andric 
33968d75effSDimitry Andric   if (status != ZX_OK) {
34068d75effSDimitry Andric     if (status != ZX_ERR_NO_MEMORY)
34168d75effSDimitry Andric       ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status, false);
34268d75effSDimitry Andric     return nullptr;
34368d75effSDimitry Andric   }
34468d75effSDimitry Andric 
34568d75effSDimitry Andric   IncreaseTotalMmap(size);
34668d75effSDimitry Andric 
34768d75effSDimitry Andric   return reinterpret_cast<void *>(addr);
34868d75effSDimitry Andric }
34968d75effSDimitry Andric 
35068d75effSDimitry Andric void UnmapOrDie(void *addr, uptr size) {
35168d75effSDimitry Andric   UnmapOrDieVmar(addr, size, _zx_vmar_root_self());
35268d75effSDimitry Andric }
35368d75effSDimitry Andric 
354fe6060f1SDimitry Andric void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
355fe6060f1SDimitry Andric   uptr beg_aligned = RoundUpTo(beg, GetPageSize());
356fe6060f1SDimitry Andric   uptr end_aligned = RoundDownTo(end, GetPageSize());
357fe6060f1SDimitry Andric   if (beg_aligned < end_aligned) {
358fe6060f1SDimitry Andric     zx_handle_t root_vmar = _zx_vmar_root_self();
359fe6060f1SDimitry Andric     CHECK_NE(root_vmar, ZX_HANDLE_INVALID);
360fe6060f1SDimitry Andric     zx_status_t status =
361fe6060f1SDimitry Andric         _zx_vmar_op_range(root_vmar, ZX_VMAR_OP_DECOMMIT, beg_aligned,
362fe6060f1SDimitry Andric                           end_aligned - beg_aligned, nullptr, 0);
363fe6060f1SDimitry Andric     CHECK_EQ(status, ZX_OK);
364fe6060f1SDimitry Andric   }
365fe6060f1SDimitry Andric }
36668d75effSDimitry Andric 
36768d75effSDimitry Andric void DumpProcessMap() {
36868d75effSDimitry Andric   // TODO(mcgrathr): write it
36968d75effSDimitry Andric   return;
37068d75effSDimitry Andric }
37168d75effSDimitry Andric 
37268d75effSDimitry Andric bool IsAccessibleMemoryRange(uptr beg, uptr size) {
37368d75effSDimitry Andric   // TODO(mcgrathr): Figure out a better way.
37468d75effSDimitry Andric   zx_handle_t vmo;
37568d75effSDimitry Andric   zx_status_t status = _zx_vmo_create(size, 0, &vmo);
37668d75effSDimitry Andric   if (status == ZX_OK) {
37768d75effSDimitry Andric     status = _zx_vmo_write(vmo, reinterpret_cast<const void *>(beg), 0, size);
37868d75effSDimitry Andric     _zx_handle_close(vmo);
37968d75effSDimitry Andric   }
38068d75effSDimitry Andric   return status == ZX_OK;
38168d75effSDimitry Andric }
38268d75effSDimitry Andric 
38368d75effSDimitry Andric // FIXME implement on this platform.
384349cc55cSDimitry Andric void GetMemoryProfile(fill_profile_f cb, uptr *stats) {}
38568d75effSDimitry Andric 
38668d75effSDimitry Andric bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
38768d75effSDimitry Andric                       uptr *read_len, uptr max_len, error_t *errno_p) {
38868d75effSDimitry Andric   zx_handle_t vmo;
38968d75effSDimitry Andric   zx_status_t status = __sanitizer_get_configuration(file_name, &vmo);
39068d75effSDimitry Andric   if (status == ZX_OK) {
39168d75effSDimitry Andric     uint64_t vmo_size;
39268d75effSDimitry Andric     status = _zx_vmo_get_size(vmo, &vmo_size);
39368d75effSDimitry Andric     if (status == ZX_OK) {
394fe6060f1SDimitry Andric       if (vmo_size < max_len)
395fe6060f1SDimitry Andric         max_len = vmo_size;
396fe6060f1SDimitry Andric       size_t map_size = RoundUpTo(max_len, GetPageSize());
39768d75effSDimitry Andric       uintptr_t addr;
39868d75effSDimitry Andric       status = _zx_vmar_map(_zx_vmar_root_self(), ZX_VM_PERM_READ, 0, vmo, 0,
39968d75effSDimitry Andric                             map_size, &addr);
40068d75effSDimitry Andric       if (status == ZX_OK) {
40168d75effSDimitry Andric         *buff = reinterpret_cast<char *>(addr);
40268d75effSDimitry Andric         *buff_size = map_size;
40368d75effSDimitry Andric         *read_len = max_len;
40468d75effSDimitry Andric       }
40568d75effSDimitry Andric     }
40668d75effSDimitry Andric     _zx_handle_close(vmo);
40768d75effSDimitry Andric   }
408fe6060f1SDimitry Andric   if (status != ZX_OK && errno_p)
409fe6060f1SDimitry Andric     *errno_p = status;
41068d75effSDimitry Andric   return status == ZX_OK;
41168d75effSDimitry Andric }
41268d75effSDimitry Andric 
41368d75effSDimitry Andric void RawWrite(const char *buffer) {
41468d75effSDimitry Andric   constexpr size_t size = 128;
41568d75effSDimitry Andric   static _Thread_local char line[size];
41668d75effSDimitry Andric   static _Thread_local size_t lastLineEnd = 0;
41768d75effSDimitry Andric   static _Thread_local size_t cur = 0;
41868d75effSDimitry Andric 
41968d75effSDimitry Andric   while (*buffer) {
42068d75effSDimitry Andric     if (cur >= size) {
42168d75effSDimitry Andric       if (lastLineEnd == 0)
42268d75effSDimitry Andric         lastLineEnd = size;
42368d75effSDimitry Andric       __sanitizer_log_write(line, lastLineEnd);
42468d75effSDimitry Andric       internal_memmove(line, line + lastLineEnd, cur - lastLineEnd);
42568d75effSDimitry Andric       cur = cur - lastLineEnd;
42668d75effSDimitry Andric       lastLineEnd = 0;
42768d75effSDimitry Andric     }
42868d75effSDimitry Andric     if (*buffer == '\n')
42968d75effSDimitry Andric       lastLineEnd = cur + 1;
43068d75effSDimitry Andric     line[cur++] = *buffer++;
43168d75effSDimitry Andric   }
43268d75effSDimitry Andric   // Flush all complete lines before returning.
43368d75effSDimitry Andric   if (lastLineEnd != 0) {
43468d75effSDimitry Andric     __sanitizer_log_write(line, lastLineEnd);
43568d75effSDimitry Andric     internal_memmove(line, line + lastLineEnd, cur - lastLineEnd);
43668d75effSDimitry Andric     cur = cur - lastLineEnd;
43768d75effSDimitry Andric     lastLineEnd = 0;
43868d75effSDimitry Andric   }
43968d75effSDimitry Andric }
44068d75effSDimitry Andric 
44168d75effSDimitry Andric void CatastrophicErrorWrite(const char *buffer, uptr length) {
44268d75effSDimitry Andric   __sanitizer_log_write(buffer, length);
44368d75effSDimitry Andric }
44468d75effSDimitry Andric 
44568d75effSDimitry Andric char **StoredArgv;
44668d75effSDimitry Andric char **StoredEnviron;
44768d75effSDimitry Andric 
44868d75effSDimitry Andric char **GetArgv() { return StoredArgv; }
44968d75effSDimitry Andric char **GetEnviron() { return StoredEnviron; }
45068d75effSDimitry Andric 
45168d75effSDimitry Andric const char *GetEnv(const char *name) {
45268d75effSDimitry Andric   if (StoredEnviron) {
45368d75effSDimitry Andric     uptr NameLen = internal_strlen(name);
45468d75effSDimitry Andric     for (char **Env = StoredEnviron; *Env != 0; Env++) {
45568d75effSDimitry Andric       if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=')
45668d75effSDimitry Andric         return (*Env) + NameLen + 1;
45768d75effSDimitry Andric     }
45868d75effSDimitry Andric   }
45968d75effSDimitry Andric   return nullptr;
46068d75effSDimitry Andric }
46168d75effSDimitry Andric 
46268d75effSDimitry Andric uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) {
46368d75effSDimitry Andric   const char *argv0 = "<UNKNOWN>";
46468d75effSDimitry Andric   if (StoredArgv && StoredArgv[0]) {
46568d75effSDimitry Andric     argv0 = StoredArgv[0];
46668d75effSDimitry Andric   }
46768d75effSDimitry Andric   internal_strncpy(buf, argv0, buf_len);
46868d75effSDimitry Andric   return internal_strlen(buf);
46968d75effSDimitry Andric }
47068d75effSDimitry Andric 
47168d75effSDimitry Andric uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
47268d75effSDimitry Andric   return ReadBinaryName(buf, buf_len);
47368d75effSDimitry Andric }
47468d75effSDimitry Andric 
47568d75effSDimitry Andric uptr MainThreadStackBase, MainThreadStackSize;
47668d75effSDimitry Andric 
47768d75effSDimitry Andric bool GetRandom(void *buffer, uptr length, bool blocking) {
47868d75effSDimitry Andric   CHECK_LE(length, ZX_CPRNG_DRAW_MAX_LEN);
47968d75effSDimitry Andric   _zx_cprng_draw(buffer, length);
48068d75effSDimitry Andric   return true;
48168d75effSDimitry Andric }
48268d75effSDimitry Andric 
483fe6060f1SDimitry Andric u32 GetNumberOfCPUs() { return zx_system_get_num_cpus(); }
48468d75effSDimitry Andric 
48568d75effSDimitry Andric uptr GetRSS() { UNIMPLEMENTED(); }
48668d75effSDimitry Andric 
487e8d8bef9SDimitry Andric void InitializePlatformCommonFlags(CommonFlags *cf) {}
488e8d8bef9SDimitry Andric 
48968d75effSDimitry Andric }  // namespace __sanitizer
49068d75effSDimitry Andric 
49168d75effSDimitry Andric using namespace __sanitizer;
49268d75effSDimitry Andric 
49368d75effSDimitry Andric extern "C" {
49468d75effSDimitry Andric void __sanitizer_startup_hook(int argc, char **argv, char **envp,
49568d75effSDimitry Andric                               void *stack_base, size_t stack_size) {
49668d75effSDimitry Andric   __sanitizer::StoredArgv = argv;
49768d75effSDimitry Andric   __sanitizer::StoredEnviron = envp;
49868d75effSDimitry Andric   __sanitizer::MainThreadStackBase = reinterpret_cast<uintptr_t>(stack_base);
49968d75effSDimitry Andric   __sanitizer::MainThreadStackSize = stack_size;
50068d75effSDimitry Andric }
50168d75effSDimitry Andric 
50268d75effSDimitry Andric void __sanitizer_set_report_path(const char *path) {
50368d75effSDimitry Andric   // Handle the initialization code in each sanitizer, but no other calls.
50468d75effSDimitry Andric   // This setting is never consulted on Fuchsia.
50568d75effSDimitry Andric   DCHECK_EQ(path, common_flags()->log_path);
50668d75effSDimitry Andric }
50768d75effSDimitry Andric 
50868d75effSDimitry Andric void __sanitizer_set_report_fd(void *fd) {
50968d75effSDimitry Andric   UNREACHABLE("not available on Fuchsia");
51068d75effSDimitry Andric }
511e8d8bef9SDimitry Andric 
512e8d8bef9SDimitry Andric const char *__sanitizer_get_report_path() {
513e8d8bef9SDimitry Andric   UNREACHABLE("not available on Fuchsia");
514e8d8bef9SDimitry Andric }
51568d75effSDimitry Andric }  // extern "C"
51668d75effSDimitry Andric 
51768d75effSDimitry Andric #endif  // SANITIZER_FUCHSIA
518