geode/loader/dobby/source/UserMode/UnifiedInterface/platform-posix.cc

242 lines
6.2 KiB
C++
Raw Normal View History

2022-07-30 12:24:03 -04:00
#include <errno.h>
#include <limits.h>
#include <pthread.h>
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__)
#include <pthread_np.h> // for pthread_set_name_np
#endif
#include <sched.h> // for sched_yield
#include <stdio.h>
#include <time.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/syscall.h>
#if defined(__APPLE__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
#include <sys/sysctl.h> // NOLINT, for sysctl
#endif
#include "logging/logging.h"
#include "logging/check_logging.h"
#include "UnifiedInterface/platform.h"
#if defined(__APPLE__)
#include <dlfcn.h>
#include <mach/mach.h>
#include <mach/vm_statistics.h>
#include <mach/mach_vm.h>
#include <mach/mach_init.h>
#endif
#if defined(ANDROID) && !defined(ANDROID_LOG_STDOUT)
#define ANDROID_LOG_TAG "Dobby"
#include <android/log.h>
#endif
#include <string.h>
#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<int>(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<uintptr_t>(address) % PageSize());
DCHECK_EQ(0, size % PageSize());
return munmap(address, size) == 0;
}
bool OSMemory::Release(void *address, int size) {
DCHECK_EQ(0, reinterpret_cast<uintptr_t>(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<uintptr_t>(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
}