#include #include #include #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) #include // for pthread_set_name_np #endif #include // for sched_yield #include #include #include #include #include #include #include #include #if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) #include // NOLINT, for sysctl #endif #include "logging/logging.h" #include "logging/check_logging.h" #include "UnifiedInterface/platform.h" #if defined(__APPLE__) #include #include #include #include #include #endif #if defined(ANDROID) && !defined(ANDROID_LOG_STDOUT) #define ANDROID_LOG_TAG "Dobby" #include #endif #include #if defined(__APPLE__) const int kMmapFd = VM_MAKE_TAG(255); #else const int kMmapFd = -1; #endif const int kMmapFdOffset = 0; // ================================================================ // base :: Thread using namespace base; typedef struct thread_handle_t { pthread_t thread; } thread_handle_t; void ThreadInterface::SetName(const char *name) { #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) pthread_set_name_np(pthread_self(), name); #elif defined(__APPLE__) pthread_setname_np(name); #endif } int ThreadInterface::CurrentId() { #if defined(__APPLE__) mach_port_t port = mach_thread_self(); mach_port_deallocate(mach_task_self(), port); return port; #elif defined(_POSIX_VERSION) return syscall(__NR_gettid); #endif } static void *thread_handler_wrapper(void *ctx) { ThreadInterface::Delegate *d = (ThreadInterface::Delegate *)ctx; d->ThreadMain(); return nullptr; } bool ThreadInterface::Create(ThreadInterface::Delegate *delegate, ThreadHandle *handle) { thread_handle_t *handle_impl = new thread_handle_t; int err = 0; err = pthread_create(&(handle_impl->thread), nullptr, thread_handler_wrapper, delegate); if (err != 0) { FATAL("pthread create failed"); return false; } return true; } Thread::Thread(const char *name) { strncpy(name_, name, sizeof(name_)); } bool Thread::Start() { if (ThreadInterface::Create(this, &handle_) == false) { return false; } return true; } // ================================================================ // base :: OSMemory static int GetProtectionFromMemoryPermission(MemoryPermission access) { switch (access) { case MemoryPermission::kNoAccess: return PROT_NONE; case MemoryPermission::kRead: return PROT_READ; case MemoryPermission::kReadWrite: return PROT_READ | PROT_WRITE #if defined(__APPLE__) | VM_PROT_COPY #endif ; case MemoryPermission::kReadWriteExecute: return PROT_READ | PROT_WRITE | PROT_EXEC #if defined(__APPLE__) | VM_PROT_COPY #endif ; case MemoryPermission::kReadExecute: return PROT_READ | PROT_EXEC; } UNREACHABLE(); } int OSMemory::AllocPageSize() { return OSMemory::PageSize(); } int OSMemory::PageSize() { return static_cast(sysconf(_SC_PAGESIZE)); } void *OSMemory::Allocate(void *address, int size, MemoryPermission access) { int prot = GetProtectionFromMemoryPermission(access); int flags = MAP_PRIVATE | MAP_ANONYMOUS; if (address != NULL) { flags = flags | MAP_FIXED; } void *result = mmap(address, size, prot, flags, kMmapFd, kMmapFdOffset); if (result == MAP_FAILED) return nullptr; return result; } bool OSMemory::Free(void *address, const int size) { DCHECK_EQ(0, reinterpret_cast(address) % PageSize()); DCHECK_EQ(0, size % PageSize()); return munmap(address, size) == 0; } bool OSMemory::Release(void *address, int size) { DCHECK_EQ(0, reinterpret_cast(address) % PageSize()); DCHECK_EQ(0, size % PageSize()); return munmap(address, size) == 0; } // static bool OSMemory::SetPermission(void *address, int size, MemoryPermission access) { DLOG(0, "SetPermission 1"); DCHECK_EQ(0, reinterpret_cast(address) % PageSize()); DLOG(0, "SetPermission 2"); DCHECK_EQ(0, size % PageSize()); DLOG(0, "SetPermission 3"); int prot = GetProtectionFromMemoryPermission(access); DLOG(0, "SetPermission 4 %p %d %d", address, size, prot); #if defined(__APPLE__) int ret = mach_vm_protect(mach_task_self(), (mach_vm_address_t)address, size, FALSE, prot); #else int ret = mprotect(address, size, prot); #endif DLOG(0, "SetPermission 4.5"); if (ret == 0 && access == MemoryPermission::kNoAccess) { // This is advisory; ignore errors and continue execution. // ReclaimInaccessibleMemory(address, size); } if (ret) { FATAL("[!] %s\n", ((const char *)strerror(errno))); } // For accounting purposes, we want to call MADV_FREE_REUSE on macOS after // changing permissions away from MemoryPermission::kNoAccess. Since this // state is not kept at this layer, we always call this if access != kNoAccess. // The cost is a syscall that effectively no-ops. // TODO(erikchen): Fix this to only call MADV_FREE_REUSE when necessary. // https://crbug.com/823915 #if defined(OS_MACOSX) DLOG(0, "SetPermission 5"); if (access != MemoryPermission::kNoAccess) madvise(address, size, MADV_FREE_REUSE); #endif DLOG(0, "SetPermission 6"); return ret == 0; } // ================================================================ // base :: OSPrint void OSPrint::Print(const char *format, ...) { va_list args; va_start(args, format); VPrint(format, args); va_end(args); } void OSPrint::VPrint(const char *format, va_list args) { #if defined(ANDROID) && !defined(ANDROID_LOG_STDOUT) __android_log_vprint(ANDROID_LOG_INFO, ANDROID_LOG_TAG, format, args); #else vprintf(format, args); #endif } void OSPrint::PrintError(const char *format, ...) { va_list args; va_start(args, format); VPrintError(format, args); va_end(args); } void OSPrint::VPrintError(const char *format, va_list args) { #if defined(ANDROID) && !defined(ANDROID_LOG_STDOUT) __android_log_vprint(ANDROID_LOG_ERROR, LOG_TAG, format, args); #else vfprintf(stderr, format, args); #endif }