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
internal__exit(int exitcode)3268d75effSDimitry Andric void NORETURN internal__exit(int exitcode) { _zx_process_exit(exitcode); }
3368d75effSDimitry Andric
internal_sched_yield()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
internal_usleep(u64 useconds)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
NanoTime()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
MonotonicNanoTime()5468d75effSDimitry Andric u64 MonotonicNanoTime() { return _zx_clock_get_monotonic(); }
5568d75effSDimitry Andric
internal_getpid()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
internal_dlinfo(void * handle,int request,void * p)67fe6060f1SDimitry Andric int internal_dlinfo(void *handle, int request, void *p) { UNIMPLEMENTED(); }
685ffd83dbSDimitry Andric
GetThreadSelf()6968d75effSDimitry Andric uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); }
7068d75effSDimitry Andric
GetTid()7168d75effSDimitry Andric tid_t GetTid() { return GetThreadSelf(); }
7268d75effSDimitry Andric
Abort()7368d75effSDimitry Andric void Abort() { abort(); }
7468d75effSDimitry Andric
Atexit(void (* function)(void))7568d75effSDimitry Andric int Atexit(void (*function)(void)) { return atexit(function); }
7668d75effSDimitry Andric
GetThreadStackTopAndBottom(bool,uptr * stack_top,uptr * stack_bottom)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
InitializePlatformEarly()8968d75effSDimitry Andric void InitializePlatformEarly() {}
CheckASLR()9068d75effSDimitry Andric void CheckASLR() {}
CheckMPROTECT()9168d75effSDimitry Andric void CheckMPROTECT() {}
PlatformPrepareForSandboxing(void * args)9281ad6265SDimitry Andric void PlatformPrepareForSandboxing(void *args) {}
DisableCoreDumperIfNecessary()9368d75effSDimitry Andric void DisableCoreDumperIfNecessary() {}
InstallDeadlySignalHandlers(SignalHandlerType handler)9468d75effSDimitry Andric void InstallDeadlySignalHandlers(SignalHandlerType handler) {}
SetAlternateSignalStack()9568d75effSDimitry Andric void SetAlternateSignalStack() {}
UnsetAlternateSignalStack()9668d75effSDimitry Andric void UnsetAlternateSignalStack() {}
InitTlsSize()9768d75effSDimitry Andric void InitTlsSize() {}
9868d75effSDimitry Andric
IsStackOverflow() const9968d75effSDimitry Andric bool SignalContext::IsStackOverflow() const { return false; }
DumpAllRegisters(void * context)10068d75effSDimitry Andric void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); }
Describe() const10168d75effSDimitry Andric const char *SignalContext::Describe() const { UNIMPLEMENTED(); }
10268d75effSDimitry Andric
FutexWait(atomic_uint32_t * p,u32 cmp)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
FutexWake(atomic_uint32_t * p,u32 count)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
GetPageSize()115fe6060f1SDimitry Andric uptr GetPageSize() { return _zx_system_get_page_size(); }
11668d75effSDimitry Andric
GetMmapGranularity()117fe6060f1SDimitry Andric uptr GetMmapGranularity() { return _zx_system_get_page_size(); }
11868d75effSDimitry Andric
11968d75effSDimitry Andric sanitizer_shadow_bounds_t ShadowBounds;
12068d75effSDimitry Andric
InitShadowBounds()121fe6060f1SDimitry Andric void InitShadowBounds() { ShadowBounds = __sanitizer_shadow_bounds(); }
122fe6060f1SDimitry Andric
GetMaxUserVirtualAddress()12368d75effSDimitry Andric uptr GetMaxUserVirtualAddress() {
124fe6060f1SDimitry Andric InitShadowBounds();
12568d75effSDimitry Andric return ShadowBounds.memory_limit - 1;
12668d75effSDimitry Andric }
12768d75effSDimitry Andric
GetMaxVirtualAddress()12868d75effSDimitry Andric uptr GetMaxVirtualAddress() { return GetMaxUserVirtualAddress(); }
12968d75effSDimitry Andric
ErrorIsOOM(error_t err)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
GetSanitizerHeapVmar(zx_handle_t * vmar)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
TryVmoMapSanitizerVmar(zx_vm_option_t options,size_t vmar_offset,zx_handle_t vmo,size_t size,uintptr_t * addr,zx_handle_t * vmar_used=nullptr)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
DoAnonymousMmapOrDie(uptr size,const char * mem_type,bool raw_report,bool die_for_nomem)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
MmapOrDie(uptr size,const char * mem_type,bool raw_report)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
MmapNoReserveOrDie(uptr size,const char * mem_type)22268d75effSDimitry Andric void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
22368d75effSDimitry Andric return MmapOrDie(size, mem_type);
22468d75effSDimitry Andric }
22568d75effSDimitry Andric
MmapOrDieOnFatalError(uptr size,const char * mem_type)22668d75effSDimitry Andric void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
22768d75effSDimitry Andric return DoAnonymousMmapOrDie(size, mem_type, false, false);
22868d75effSDimitry Andric }
22968d75effSDimitry Andric
Init(uptr init_size,const char * name,uptr fixed_addr)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
DoMmapFixedOrDie(zx_handle_t vmar,uptr fixed_addr,uptr map_size,void * base,const char * name,bool die_for_nomem)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
Map(uptr fixed_addr,uptr map_size,const char * name)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
MapOrDie(uptr fixed_addr,uptr map_size,const char * name)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
UnmapOrDieVmar(void * addr,uptr size,zx_handle_t target_vmar,bool raw_report)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
Unmap(uptr addr,uptr size)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.
MmapFixedNoAccess(uptr fixed_addr,uptr size,const char * name)33368d75effSDimitry Andric void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {
33468d75effSDimitry Andric UNIMPLEMENTED();
33568d75effSDimitry Andric }
33668d75effSDimitry Andric
MprotectNoAccess(uptr addr,uptr size)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
MprotectReadOnly(uptr addr,uptr size)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
MprotectReadWrite(uptr addr,uptr size)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
MmapAlignedOrDieOnFatalError(uptr size,uptr alignment,const char * mem_type)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
UnmapOrDie(void * addr,uptr size,bool raw_report)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
ReleaseMemoryPagesToOS(uptr beg,uptr end)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
DumpProcessMap()43268d75effSDimitry Andric void DumpProcessMap() {
43368d75effSDimitry Andric // TODO(mcgrathr): write it
43468d75effSDimitry Andric return;
43568d75effSDimitry Andric }
43668d75effSDimitry Andric
IsAccessibleMemoryRange(uptr beg,uptr size)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.
GetMemoryProfile(fill_profile_f cb,uptr * stats)449349cc55cSDimitry Andric void GetMemoryProfile(fill_profile_f cb, uptr *stats) {}
45068d75effSDimitry Andric
ReadFileToBuffer(const char * file_name,char ** buff,uptr * buff_size,uptr * read_len,uptr max_len,error_t * errno_p)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
RawWrite(const char * buffer)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
CatastrophicErrorWrite(const char * buffer,uptr length)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
GetArgv()49268d75effSDimitry Andric char **GetArgv() { return StoredArgv; }
GetEnviron()49368d75effSDimitry Andric char **GetEnviron() { return StoredEnviron; }
49468d75effSDimitry Andric
GetEnv(const char * name)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
ReadBinaryName(char * buf,uptr buf_len)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
ReadLongProcessName(char * buf,uptr buf_len)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
GetRandom(void * buffer,uptr length,bool blocking)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
GetNumberOfCPUs()527fe6060f1SDimitry Andric u32 GetNumberOfCPUs() { return zx_system_get_num_cpus(); }
52868d75effSDimitry Andric
GetRSS()52968d75effSDimitry Andric uptr GetRSS() { UNIMPLEMENTED(); }
53068d75effSDimitry Andric
internal_start_thread(void * (* func)(void * arg),void * arg)5310eae32dcSDimitry Andric void *internal_start_thread(void *(*func)(void *arg), void *arg) { return 0; }
internal_join_thread(void * th)5320eae32dcSDimitry Andric void internal_join_thread(void *th) {}
5330eae32dcSDimitry Andric
InitializePlatformCommonFlags(CommonFlags * cf)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" {
__sanitizer_startup_hook(int argc,char ** argv,char ** envp,void * stack_base,size_t stack_size)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
__sanitizer_set_report_path(const char * path)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
__sanitizer_set_report_fd(void * fd)55568d75effSDimitry Andric void __sanitizer_set_report_fd(void *fd) {
55668d75effSDimitry Andric UNREACHABLE("not available on Fuchsia");
55768d75effSDimitry Andric }
558e8d8bef9SDimitry Andric
__sanitizer_get_report_path()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