mirror of
https://github.com/decompals/wibo.git
synced 2025-12-12 06:45:05 +00:00
Initial macOS support (x86_64 with Rosetta 2)
This commit is contained in:
@@ -2,6 +2,13 @@ cmake_minimum_required(VERSION 3.13)
|
|||||||
|
|
||||||
project(wibo LANGUAGES ASM C CXX)
|
project(wibo LANGUAGES ASM C CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
|
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||||
|
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.15")
|
||||||
|
set(CMAKE_OSX_ARCHITECTURES "x86_64" CACHE INTERNAL "" FORCE)
|
||||||
|
endif()
|
||||||
|
|
||||||
set(WIBO_VERSION "" CACHE STRING "Version string for the wibo binary; if empty, attempts to use git describe")
|
set(WIBO_VERSION "" CACHE STRING "Version string for the wibo binary; if empty, attempts to use git describe")
|
||||||
|
|
||||||
if(NOT "${WIBO_VERSION}" STREQUAL "")
|
if(NOT "${WIBO_VERSION}" STREQUAL "")
|
||||||
@@ -92,13 +99,15 @@ FetchContent_MakeAvailable(mimalloc)
|
|||||||
|
|
||||||
# Disable `note: the alignment of '_Atomic long long int' fields changed in GCC 11.1`
|
# Disable `note: the alignment of '_Atomic long long int' fields changed in GCC 11.1`
|
||||||
target_compile_options(mimalloc-obj PRIVATE -Wno-psabi)
|
target_compile_options(mimalloc-obj PRIVATE -Wno-psabi)
|
||||||
target_compile_definitions(mimalloc-obj PRIVATE MI_USE_BUILTIN_THREAD_POINTER=1)
|
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
target_compile_definitions(mimalloc-obj PRIVATE MI_USE_BUILTIN_THREAD_POINTER=1)
|
||||||
|
endif()
|
||||||
if (WIBO_64)
|
if (WIBO_64)
|
||||||
# Disable a noisy warning on startup
|
# Disable a noisy warning on startup
|
||||||
target_compile_definitions(mimalloc-obj PRIVATE MI_DEBUG=0)
|
target_compile_definitions(mimalloc-obj PRIVATE MI_DEBUG=0)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WIBO_ENABLE_LIBURING)
|
if (WIBO_ENABLE_LIBURING AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
liburing
|
liburing
|
||||||
GIT_REPOSITORY https://github.com/axboe/liburing.git
|
GIT_REPOSITORY https://github.com/axboe/liburing.git
|
||||||
@@ -142,7 +151,6 @@ add_executable(wibo
|
|||||||
dll/advapi32/wincrypt.cpp
|
dll/advapi32/wincrypt.cpp
|
||||||
dll/advapi32/winreg.cpp
|
dll/advapi32/winreg.cpp
|
||||||
dll/bcrypt.cpp
|
dll/bcrypt.cpp
|
||||||
dll/crt.cpp
|
|
||||||
dll/kernel32.cpp
|
dll/kernel32.cpp
|
||||||
dll/kernel32/debugapi.cpp
|
dll/kernel32/debugapi.cpp
|
||||||
dll/kernel32/errhandlingapi.cpp
|
dll/kernel32/errhandlingapi.cpp
|
||||||
@@ -169,7 +177,6 @@ add_executable(wibo
|
|||||||
dll/kernel32/wow64apiset.cpp
|
dll/kernel32/wow64apiset.cpp
|
||||||
dll/lmgr.cpp
|
dll/lmgr.cpp
|
||||||
dll/mscoree.cpp
|
dll/mscoree.cpp
|
||||||
dll/msvcrt.cpp
|
|
||||||
dll/ntdll.cpp
|
dll/ntdll.cpp
|
||||||
dll/ole32.cpp
|
dll/ole32.cpp
|
||||||
dll/rpcrt4.cpp
|
dll/rpcrt4.cpp
|
||||||
@@ -178,7 +185,6 @@ add_executable(wibo
|
|||||||
dll/version.cpp
|
dll/version.cpp
|
||||||
src/access.cpp
|
src/access.cpp
|
||||||
src/async_io.cpp
|
src/async_io.cpp
|
||||||
src/async_io_epoll.cpp
|
|
||||||
src/errors.cpp
|
src/errors.cpp
|
||||||
src/files.cpp
|
src/files.cpp
|
||||||
src/handles.cpp
|
src/handles.cpp
|
||||||
@@ -186,23 +192,52 @@ add_executable(wibo
|
|||||||
src/loader.cpp
|
src/loader.cpp
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/modules.cpp
|
src/modules.cpp
|
||||||
src/processes.cpp
|
src/processes_common.cpp
|
||||||
src/resources.cpp
|
src/resources.cpp
|
||||||
src/setup.S
|
src/setup.S
|
||||||
src/strutil.cpp
|
src/strutil.cpp
|
||||||
src/tls.cpp
|
src/tls.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
target_sources(wibo PRIVATE
|
||||||
|
src/async_io_epoll.cpp
|
||||||
|
src/processes_linux.cpp
|
||||||
|
)
|
||||||
|
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||||
|
target_sources(wibo PRIVATE
|
||||||
|
src/processes_darwin.cpp
|
||||||
|
src/setup_darwin.cpp
|
||||||
|
)
|
||||||
|
set_source_files_properties(src/setup_darwin.cpp PROPERTIES COMPILE_FLAGS "-fms-extensions")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Unsupported platform for ProcessManager")
|
||||||
|
endif()
|
||||||
target_compile_definitions(wibo PRIVATE _GNU_SOURCE _FILE_OFFSET_BITS=64 _TIME_BITS=64)
|
target_compile_definitions(wibo PRIVATE _GNU_SOURCE _FILE_OFFSET_BITS=64 _TIME_BITS=64)
|
||||||
target_compile_features(wibo PRIVATE cxx_std_20)
|
target_compile_features(wibo PRIVATE cxx_std_20)
|
||||||
target_compile_options(wibo PRIVATE -Wall -Wextra)
|
target_compile_options(wibo PRIVATE -Wall -Wextra)
|
||||||
target_link_options(wibo PRIVATE -no-pie -Wl,--image-base=0x70000000)
|
if (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||||
|
target_link_options(wibo PRIVATE
|
||||||
|
-Wl,-no_pie,-no_fixup_chains
|
||||||
|
-Wl,-segalign,0x1000
|
||||||
|
-Wl,-pagezero_size,0x1000
|
||||||
|
-Wl,-image_base,0x7E001000
|
||||||
|
-Wl,-segaddr,RESV32,0x1000
|
||||||
|
-Wl,-segprot,RESV32,-,-
|
||||||
|
)
|
||||||
|
else()
|
||||||
|
target_link_options(wibo PRIVATE -no-pie -Wl,--image-base=0x70000000)
|
||||||
|
endif()
|
||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
target_compile_options(wibo PRIVATE -maccumulate-outgoing-args)
|
target_compile_options(wibo PRIVATE -maccumulate-outgoing-args)
|
||||||
target_link_options(wibo PRIVATE -maccumulate-outgoing-args)
|
target_link_options(wibo PRIVATE -maccumulate-outgoing-args)
|
||||||
endif()
|
endif()
|
||||||
target_include_directories(wibo PRIVATE dll src ${WIBO_GENERATED_HEADER_DIR})
|
target_include_directories(wibo PRIVATE dll src ${WIBO_GENERATED_HEADER_DIR})
|
||||||
target_link_libraries(wibo PRIVATE mimalloc-obj atomic)
|
target_link_libraries(wibo PRIVATE mimalloc-obj)
|
||||||
if (WIBO_ENABLE_LIBURING)
|
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
target_link_libraries(wibo PRIVATE atomic)
|
||||||
|
endif()
|
||||||
|
if (WIBO_ENABLE_LIBURING AND CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
target_compile_definitions(wibo PRIVATE WIBO_ENABLE_LIBURING=1)
|
target_compile_definitions(wibo PRIVATE WIBO_ENABLE_LIBURING=1)
|
||||||
target_link_libraries(wibo PRIVATE liburing)
|
target_link_libraries(wibo PRIVATE liburing)
|
||||||
target_sources(wibo PRIVATE src/async_io_uring.cpp)
|
target_sources(wibo PRIVATE src/async_io_uring.cpp)
|
||||||
@@ -216,7 +251,11 @@ find_package(Python3 COMPONENTS Interpreter REQUIRED)
|
|||||||
# Track down libclang for trampoline generation.
|
# Track down libclang for trampoline generation.
|
||||||
# find_package(Clang) ends up requiring too many dependencies,
|
# find_package(Clang) ends up requiring too many dependencies,
|
||||||
# so a quick-and-dirty manual search is done here instead.
|
# so a quick-and-dirty manual search is done here instead.
|
||||||
set(CLANG_ROOT "/usr" CACHE PATH "Path to Clang installation")
|
if (CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||||
|
set(CLANG_ROOT "/usr" CACHE PATH "Path to Clang installation")
|
||||||
|
elseif (CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
||||||
|
set(CLANG_ROOT "/Library/Developer/CommandLineTools/usr/lib" CACHE PATH "Path to Clang installation")
|
||||||
|
endif()
|
||||||
set(_LLVM_MIN_VER 17)
|
set(_LLVM_MIN_VER 17)
|
||||||
set(_LLVM_MAX_VER 25)
|
set(_LLVM_MAX_VER 25)
|
||||||
set(_CLANG_LIB_SUFFIXES "")
|
set(_CLANG_LIB_SUFFIXES "")
|
||||||
@@ -274,9 +313,7 @@ wibo_codegen_module(NAME advapi32 HEADERS
|
|||||||
)
|
)
|
||||||
wibo_codegen_module(NAME bcrypt HEADERS dll/bcrypt.h)
|
wibo_codegen_module(NAME bcrypt HEADERS dll/bcrypt.h)
|
||||||
wibo_codegen_module(NAME entry HEADERS src/entry.h)
|
wibo_codegen_module(NAME entry HEADERS src/entry.h)
|
||||||
wibo_codegen_module(NAME crt HEADERS dll/crt.h)
|
|
||||||
wibo_codegen_module(NAME mscoree HEADERS dll/mscoree.h)
|
wibo_codegen_module(NAME mscoree HEADERS dll/mscoree.h)
|
||||||
wibo_codegen_module(NAME msvcrt HEADERS dll/msvcrt.h)
|
|
||||||
wibo_codegen_module(NAME version HEADERS dll/version.h)
|
wibo_codegen_module(NAME version HEADERS dll/version.h)
|
||||||
wibo_codegen_module(NAME rpcrt4 HEADERS dll/rpcrt4.h)
|
wibo_codegen_module(NAME rpcrt4 HEADERS dll/rpcrt4.h)
|
||||||
wibo_codegen_module(NAME vcruntime HEADERS dll/vcruntime.h)
|
wibo_codegen_module(NAME vcruntime HEADERS dll/vcruntime.h)
|
||||||
@@ -432,3 +469,7 @@ if (WIBO_ENABLE_FIXTURE_TESTS)
|
|||||||
add_test(NAME wibo.build_fixtures COMMAND ${_wibo_fixture_build_command})
|
add_test(NAME wibo.build_fixtures COMMAND ${_wibo_fixture_build_command})
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (NOT TARGET wibo_test_fixtures)
|
||||||
|
add_custom_target(wibo_test_fixtures)
|
||||||
|
endif()
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ BOOL WINAPI OpenProcessToken(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE
|
|||||||
}
|
}
|
||||||
Pin<ProcessObject> obj;
|
Pin<ProcessObject> obj;
|
||||||
if (kernel32::isPseudoCurrentProcessHandle(ProcessHandle)) {
|
if (kernel32::isPseudoCurrentProcessHandle(ProcessHandle)) {
|
||||||
obj = make_pin<ProcessObject>(getpid(), -1);
|
obj = make_pin<ProcessObject>(getpid(), -1, false);
|
||||||
} else {
|
} else {
|
||||||
obj = wibo::handles().getAs<ProcessObject>(ProcessHandle);
|
obj = wibo::handles().getAs<ProcessObject>(ProcessHandle);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,12 +92,15 @@ BOOL WINAPI CryptGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer) {
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
arc4random_buf(pbBuffer, dwLen);
|
||||||
|
#else
|
||||||
ssize_t ret = getrandom(pbBuffer, dwLen, 0);
|
ssize_t ret = getrandom(pbBuffer, dwLen, 0);
|
||||||
if (ret < 0 || static_cast<DWORD>(ret) != dwLen) {
|
if (ret < 0 || static_cast<DWORD>(ret) != dwLen) {
|
||||||
kernel32::setLastError(ERROR_NOT_SUPPORTED);
|
kernel32::setLastError(ERROR_NOT_SUPPORTED);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,9 @@ constexpr ULONG BCRYPT_RNG_USE_ENTROPY_IN_BUFFER = 0x00000001;
|
|||||||
constexpr ULONG BCRYPT_USE_SYSTEM_PREFERRED_RNG = 0x00000002;
|
constexpr ULONG BCRYPT_USE_SYSTEM_PREFERRED_RNG = 0x00000002;
|
||||||
|
|
||||||
bool fillWithSystemRandom(PUCHAR buffer, size_t length) {
|
bool fillWithSystemRandom(PUCHAR buffer, size_t length) {
|
||||||
|
#ifdef __APPLE__
|
||||||
|
arc4random_buf(buffer, length);
|
||||||
|
#else
|
||||||
while (length > 0) {
|
while (length > 0) {
|
||||||
ssize_t written = getrandom(buffer, length, 0);
|
ssize_t written = getrandom(buffer, length, 0);
|
||||||
if (written < 0) {
|
if (written < 0) {
|
||||||
@@ -27,6 +30,7 @@ bool fillWithSystemRandom(PUCHAR buffer, size_t length) {
|
|||||||
buffer += written;
|
buffer += written;
|
||||||
length -= static_cast<size_t>(written);
|
length -= static_cast<size_t>(written);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
478
dll/crt.cpp
478
dll/crt.cpp
@@ -1,478 +0,0 @@
|
|||||||
#include "crt.h"
|
|
||||||
|
|
||||||
#include "common.h"
|
|
||||||
#include "context.h"
|
|
||||||
#include "crt_trampolines.h"
|
|
||||||
#include "heap.h"
|
|
||||||
#include "kernel32/internal.h"
|
|
||||||
#include "modules.h"
|
|
||||||
#include "types.h"
|
|
||||||
|
|
||||||
#include <csignal>
|
|
||||||
#include <cstdarg>
|
|
||||||
#include <cstdio>
|
|
||||||
#include <cstdlib>
|
|
||||||
#include <cstring>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
|
|
||||||
FILE *mapToHostFile(_FILE *file) {
|
|
||||||
if (!file)
|
|
||||||
return nullptr;
|
|
||||||
switch (file->_file) {
|
|
||||||
case STDIN_FILENO:
|
|
||||||
return stdin;
|
|
||||||
case STDOUT_FILENO:
|
|
||||||
return stdout;
|
|
||||||
case STDERR_FILENO:
|
|
||||||
return stderr;
|
|
||||||
default:
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace crt {
|
|
||||||
|
|
||||||
int _commode = 0;
|
|
||||||
int _fmode = 0;
|
|
||||||
|
|
||||||
std::vector<_PVFV> atexitFuncs;
|
|
||||||
_invalid_parameter_handler invalidParameterHandler = nullptr;
|
|
||||||
|
|
||||||
GUEST_PTR guestArgv = GUEST_NULL;
|
|
||||||
GUEST_PTR guestEnviron = GUEST_NULL;
|
|
||||||
|
|
||||||
void CDECL _initterm(GUEST_PTR *ppfn, GUEST_PTR *end) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("_initterm(%p, %p)\n", ppfn, end);
|
|
||||||
do {
|
|
||||||
if (GUEST_PTR pfn = *++ppfn) {
|
|
||||||
DEBUG_LOG("-> calling %p\n", pfn);
|
|
||||||
auto fn = reinterpret_cast<_PVFV>(fromGuestPtr(pfn));
|
|
||||||
call__PVFV(fn);
|
|
||||||
}
|
|
||||||
} while (ppfn < end);
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL _initterm_e(GUEST_PTR *ppfn, GUEST_PTR *end) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("_initterm_e(%p, %p)\n", ppfn, end);
|
|
||||||
do {
|
|
||||||
if (GUEST_PTR pfn = *++ppfn) {
|
|
||||||
DEBUG_LOG("-> calling %p\n", pfn);
|
|
||||||
auto fn = reinterpret_cast<_PIFV>(fromGuestPtr(pfn));
|
|
||||||
int err = call__PIFV(fn);
|
|
||||||
if (err)
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
} while (ppfn < end);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDECL _set_app_type(_crt_app_type type) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("STUB: _set_app_type(%i)\n", type);
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL _set_fmode(int mode) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("_set_fmode(%i)\n", mode);
|
|
||||||
_fmode = mode;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
GUEST_PTR CDECL __p__commode() {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("__p__commode()\n");
|
|
||||||
return toGuestPtr(&_commode);
|
|
||||||
}
|
|
||||||
|
|
||||||
GUEST_PTR CDECL __p__fmode() {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("__p__fmode()\n");
|
|
||||||
return toGuestPtr(&_fmode);
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL _crt_atexit(void (*func)()) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("_crt_atexit(%p)\n", func);
|
|
||||||
atexitFuncs.push_back(func);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL _configure_narrow_argv(_crt_argv_mode mode) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("STUB: _configure_narrow_argv(%i)\n", mode);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
_invalid_parameter_handler CDECL _set_invalid_parameter_handler(_invalid_parameter_handler newHandler) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("STUB: _set_invalid_parameter_handler(%p)\n", newHandler);
|
|
||||||
_invalid_parameter_handler oldHandler = invalidParameterHandler;
|
|
||||||
invalidParameterHandler = newHandler;
|
|
||||||
return oldHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("STUB: _controlfp_s(%p, %u, %u)\n", currentControl, newControl, mask);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL _configthreadlocale(int per_thread_locale_type) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("STUB: _configthreadlocale(%i)\n", per_thread_locale_type);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL _initialize_narrow_environment() {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("STUB: _initialize_narrow_environment()\n");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL _set_new_mode(int newhandlermode) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("STUB: _set_new_mode(%i)\n", newhandlermode);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
GUEST_PTR CDECL _get_initial_narrow_environment() {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("_get_initial_narrow_environment()\n");
|
|
||||||
if (guestEnviron == GUEST_NULL) {
|
|
||||||
int count = 0;
|
|
||||||
while (environ[count]) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
GUEST_PTR *buf = reinterpret_cast<GUEST_PTR *>(wibo::heap::guestMalloc(count * sizeof(GUEST_PTR)));
|
|
||||||
if (!buf) {
|
|
||||||
return GUEST_NULL;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
size_t len = ::strlen(environ[i]);
|
|
||||||
char *str = reinterpret_cast<char *>(wibo::heap::guestMalloc(len + 1));
|
|
||||||
::memcpy(str, environ[i], len + 1);
|
|
||||||
buf[i] = toGuestPtr(str);
|
|
||||||
}
|
|
||||||
guestEnviron = toGuestPtr(buf);
|
|
||||||
}
|
|
||||||
return guestEnviron;
|
|
||||||
}
|
|
||||||
|
|
||||||
GUEST_PTR CDECL __p__environ() {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("__p__environ()\n");
|
|
||||||
if (guestEnviron == GUEST_NULL) {
|
|
||||||
int count = 0;
|
|
||||||
while (environ[count]) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
GUEST_PTR *buf = reinterpret_cast<GUEST_PTR *>(wibo::heap::guestMalloc(count * sizeof(GUEST_PTR)));
|
|
||||||
if (!buf) {
|
|
||||||
return GUEST_NULL;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
size_t len = ::strlen(environ[i]);
|
|
||||||
char *str = reinterpret_cast<char *>(wibo::heap::guestMalloc(len + 1));
|
|
||||||
::memcpy(str, environ[i], len + 1);
|
|
||||||
buf[i] = toGuestPtr(str);
|
|
||||||
}
|
|
||||||
guestEnviron = toGuestPtr(buf);
|
|
||||||
}
|
|
||||||
return toGuestPtr(&environ);
|
|
||||||
}
|
|
||||||
|
|
||||||
GUEST_PTR CDECL __p___argv() {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("__p___argv()\n");
|
|
||||||
if (guestArgv == GUEST_NULL) {
|
|
||||||
int count = 0;
|
|
||||||
while (wibo::argv[count]) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
GUEST_PTR *buf = reinterpret_cast<GUEST_PTR *>(wibo::heap::guestMalloc(count * sizeof(GUEST_PTR)));
|
|
||||||
if (!buf) {
|
|
||||||
return GUEST_NULL;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < count; i++) {
|
|
||||||
size_t len = ::strlen(wibo::argv[i]);
|
|
||||||
char *str = reinterpret_cast<char *>(wibo::heap::guestMalloc(len + 1));
|
|
||||||
::memcpy(str, wibo::argv[i], len + 1);
|
|
||||||
buf[i] = toGuestPtr(str);
|
|
||||||
}
|
|
||||||
guestArgv = toGuestPtr(buf);
|
|
||||||
}
|
|
||||||
return toGuestPtr(&guestArgv);
|
|
||||||
}
|
|
||||||
|
|
||||||
GUEST_PTR CDECL __p___argc() {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("__p___argc()\n");
|
|
||||||
return toGuestPtr(&wibo::argc);
|
|
||||||
}
|
|
||||||
|
|
||||||
SIZE_T CDECL strlen(const char *str) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
VERBOSE_LOG("strlen(%p)\n", str);
|
|
||||||
return ::strlen(str);
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL strcmp(const char *lhs, const char *rhs) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
VERBOSE_LOG("strcmp(%p, %p)\n", lhs, rhs);
|
|
||||||
return ::strcmp(lhs, rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL strncmp(const char *lhs, const char *rhs, SIZE_T count) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
VERBOSE_LOG("strncmp(%p, %p, %zu)\n", lhs, rhs, count);
|
|
||||||
return ::strncmp(lhs, rhs, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *CDECL strcpy(char *dest, const char *src) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
VERBOSE_LOG("strcpy(%p, %p)\n", dest, src);
|
|
||||||
return ::strcpy(dest, src);
|
|
||||||
}
|
|
||||||
|
|
||||||
char *CDECL strncpy(char *dest, const char *src, SIZE_T count) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
VERBOSE_LOG("strncpy(%p, %p, %zu)\n", dest, src, count);
|
|
||||||
return ::strncpy(dest, src, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *CDECL strrchr(const char *str, int ch) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
VERBOSE_LOG("strrchr(%p, %i)\n", str, ch);
|
|
||||||
return ::strrchr(str, ch);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *CDECL malloc(SIZE_T size) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
VERBOSE_LOG("malloc(%zu)\n", size);
|
|
||||||
return wibo::heap::guestMalloc(size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *CDECL calloc(SIZE_T count, SIZE_T size) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
VERBOSE_LOG("calloc(%zu, %zu)\n", count, size);
|
|
||||||
return wibo::heap::guestCalloc(count, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *CDECL realloc(void *ptr, SIZE_T newSize) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
VERBOSE_LOG("realloc(%p, %zu)\n", ptr, newSize);
|
|
||||||
return wibo::heap::guestRealloc(ptr, newSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDECL free(void *ptr) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
VERBOSE_LOG("free(%p)\n", ptr);
|
|
||||||
wibo::heap::guestFree(ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *CDECL memcpy(void *dest, const void *src, SIZE_T count) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
VERBOSE_LOG("memcpy(%p, %p, %zu)\n", dest, src, count);
|
|
||||||
return std::memcpy(dest, src, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *CDECL memmove(void *dest, const void *src, SIZE_T count) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
VERBOSE_LOG("memmove(%p, %p, %zu)\n", dest, src, count);
|
|
||||||
return std::memmove(dest, src, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *CDECL memset(void *dest, int ch, SIZE_T count) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
VERBOSE_LOG("memset(%p, %i, %zu)\n", dest, ch, count);
|
|
||||||
return std::memset(dest, ch, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL memcmp(const void *lhs, const void *rhs, SIZE_T count) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
VERBOSE_LOG("memcmp(%p, %p, %zu)\n", lhs, rhs, count);
|
|
||||||
return std::memcmp(lhs, rhs, count);
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL __setusermatherr(void *handler) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("STUB: __setusermatherr(%p)\n", handler);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL _initialize_onexit_table(_onexit_table_t *table) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("_initialize_onexit_table(%p)\n", table);
|
|
||||||
if (!table)
|
|
||||||
return -1;
|
|
||||||
if (table->first != table->last)
|
|
||||||
return 0;
|
|
||||||
table->first = GUEST_NULL;
|
|
||||||
table->last = GUEST_NULL;
|
|
||||||
table->end = GUEST_NULL;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL _register_onexit_function(_onexit_table_t *table, _onexit_t func) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("_register_onexit_function(%p, %p)\n", table, func);
|
|
||||||
if (!table || !func)
|
|
||||||
return -1;
|
|
||||||
GUEST_PTR *first = reinterpret_cast<GUEST_PTR *>(fromGuestPtr(table->first));
|
|
||||||
GUEST_PTR *last = reinterpret_cast<GUEST_PTR *>(fromGuestPtr(table->last));
|
|
||||||
GUEST_PTR *end = reinterpret_cast<GUEST_PTR *>(fromGuestPtr(table->end));
|
|
||||||
if (last == end) {
|
|
||||||
size_t count = end - first;
|
|
||||||
size_t newCount = count + 1;
|
|
||||||
if (newCount <= 0)
|
|
||||||
return -1;
|
|
||||||
GUEST_PTR *newTable = static_cast<GUEST_PTR *>(wibo::heap::guestRealloc(first, newCount * sizeof(GUEST_PTR)));
|
|
||||||
if (!newTable)
|
|
||||||
return -1;
|
|
||||||
table->first = toGuestPtr(newTable);
|
|
||||||
last = newTable + count;
|
|
||||||
table->end = toGuestPtr(newTable + newCount);
|
|
||||||
}
|
|
||||||
*last = toGuestPtr(reinterpret_cast<void *>(func));
|
|
||||||
table->last = toGuestPtr(last + 1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL _execute_onexit_table(_onexit_table_t *table) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("_execute_onexit_table(%p)\n", table);
|
|
||||||
if (!table)
|
|
||||||
return -1;
|
|
||||||
GUEST_PTR *first = reinterpret_cast<GUEST_PTR *>(fromGuestPtr(table->first));
|
|
||||||
GUEST_PTR *last = reinterpret_cast<GUEST_PTR *>(fromGuestPtr(table->last));
|
|
||||||
for (auto it = first; it != last; ++it) {
|
|
||||||
_onexit_t fn = reinterpret_cast<_onexit_t>(fromGuestPtr(*it));
|
|
||||||
DEBUG_LOG("Calling onexit_table function %p\n", fn);
|
|
||||||
call__onexit_t(fn);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDECL exit(int status) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("exit(%i)\n", status);
|
|
||||||
_cexit();
|
|
||||||
kernel32::exitInternal(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDECL _cexit() {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("_cexit()\n");
|
|
||||||
for (auto it = atexitFuncs.rbegin(); it != atexitFuncs.rend(); ++it) {
|
|
||||||
DEBUG_LOG("Calling atexit function %p\n", *it);
|
|
||||||
call__PVFV(*it);
|
|
||||||
}
|
|
||||||
std::fflush(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDECL _exit(int status) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("_exit(%i)\n", status);
|
|
||||||
kernel32::exitInternal(status);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CDECL abort() {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("abort()\n");
|
|
||||||
std::abort();
|
|
||||||
}
|
|
||||||
|
|
||||||
signal_handler CDECL signal(int signum, signal_handler handler) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("signal(%i, %p)\n", signum, handler);
|
|
||||||
return std::signal(signum, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
void *CDECL __acrt_iob_func(unsigned int index) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("__acrt_iob_func(%u)\n", index);
|
|
||||||
if (index == 0)
|
|
||||||
return stdin;
|
|
||||||
if (index == 1)
|
|
||||||
return stdout;
|
|
||||||
if (index == 2)
|
|
||||||
return stderr;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL_NO_CONV __stdio_common_vfprintf(ULONGLONG options, _FILE *stream, const char *format, void *locale,
|
|
||||||
va_list args) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("__stdio_common_vfprintf(%llu, %p, %s, %p, %p)\n", options, stream, format, locale, args);
|
|
||||||
FILE *hostFile = mapToHostFile(stream);
|
|
||||||
if (!hostFile)
|
|
||||||
return -1;
|
|
||||||
return vfprintf(hostFile, format, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL_NO_CONV __stdio_common_vsprintf(ULONGLONG options, char *buffer, SIZE_T len, const char *format, void *locale,
|
|
||||||
va_list args) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("__stdio_common_vsprintf(%llu, %p, %zu, %s, %p, ...)\n", options, buffer, len, format, locale);
|
|
||||||
if (!buffer || !format)
|
|
||||||
return -1;
|
|
||||||
int result = vsnprintf(buffer, len, format, args);
|
|
||||||
if (result < 0)
|
|
||||||
return -1;
|
|
||||||
if (len > 0 && static_cast<SIZE_T>(result) >= len)
|
|
||||||
return -1;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
static thread_local sort_compare currentCompare = nullptr;
|
|
||||||
|
|
||||||
static int doCompare(const void *a, const void *b) { return call_sort_compare(currentCompare, a, b); }
|
|
||||||
|
|
||||||
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
DEBUG_LOG("qsort(%p, %zu, %zu, %p)\n", base, num, size, compare);
|
|
||||||
currentCompare = compare;
|
|
||||||
::qsort(base, num, size, doCompare);
|
|
||||||
}
|
|
||||||
|
|
||||||
int CDECL puts(const char *str) {
|
|
||||||
HOST_CONTEXT_GUARD();
|
|
||||||
if (!str) {
|
|
||||||
str = "(null)";
|
|
||||||
}
|
|
||||||
DEBUG_LOG("puts(%s)\n", str);
|
|
||||||
if (std::fputs(str, stdout) < 0)
|
|
||||||
return EOF;
|
|
||||||
if (std::fputc('\n', stdout) == EOF)
|
|
||||||
return EOF;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace crt
|
|
||||||
|
|
||||||
#include "crt_trampolines.h"
|
|
||||||
|
|
||||||
extern const wibo::ModuleStub lib_crt = {
|
|
||||||
(const char *[]){
|
|
||||||
"api-ms-win-crt-heap-l1-1-0",
|
|
||||||
"api-ms-win-crt-locale-l1-1-0",
|
|
||||||
"api-ms-win-crt-runtime-l1-1-0",
|
|
||||||
"api-ms-win-crt-stdio-l1-1-0",
|
|
||||||
"api-ms-win-crt-string-l1-1-0",
|
|
||||||
"api-ms-win-crt-environment-l1-1-0",
|
|
||||||
"api-ms-win-crt-math-l1-1-0",
|
|
||||||
"api-ms-win-crt-private-l1-1-0",
|
|
||||||
"api-ms-win-crt-utility-l1-1-0",
|
|
||||||
nullptr,
|
|
||||||
},
|
|
||||||
crtThunkByName,
|
|
||||||
nullptr,
|
|
||||||
};
|
|
||||||
86
dll/crt.h
86
dll/crt.h
@@ -1,86 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
|
|
||||||
typedef void(_CC_CDECL *_PVFV)();
|
|
||||||
typedef int(_CC_CDECL *_PIFV)();
|
|
||||||
typedef void(_CC_CDECL *_invalid_parameter_handler)(const WCHAR *, const WCHAR *, const WCHAR *, UINT, UINT_PTR);
|
|
||||||
|
|
||||||
typedef enum _crt_app_type {
|
|
||||||
_crt_unknown_app,
|
|
||||||
_crt_console_app,
|
|
||||||
_crt_gui_app,
|
|
||||||
} _crt_app_type;
|
|
||||||
|
|
||||||
typedef enum _crt_argv_mode {
|
|
||||||
_crt_argv_no_arguments,
|
|
||||||
_crt_argv_unexpanded_arguments,
|
|
||||||
_crt_argv_expanded_arguments,
|
|
||||||
} _crt_argv_mode;
|
|
||||||
|
|
||||||
typedef void(_CC_CDECL *signal_handler)(int);
|
|
||||||
typedef int(_CC_CDECL *sort_compare)(const void *, const void *);
|
|
||||||
typedef int(_CC_CDECL *_onexit_t)();
|
|
||||||
|
|
||||||
struct _onexit_table_t {
|
|
||||||
GUEST_PTR first;
|
|
||||||
GUEST_PTR last;
|
|
||||||
GUEST_PTR end;
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace crt {
|
|
||||||
|
|
||||||
extern int _commode;
|
|
||||||
extern int _fmode;
|
|
||||||
|
|
||||||
void CDECL _initterm(GUEST_PTR *ppfn, GUEST_PTR *end);
|
|
||||||
int CDECL _initterm_e(GUEST_PTR *ppfn, GUEST_PTR *end);
|
|
||||||
void CDECL _set_app_type(_crt_app_type type);
|
|
||||||
int CDECL _set_fmode(int mode);
|
|
||||||
GUEST_PTR CDECL __p__commode();
|
|
||||||
GUEST_PTR CDECL __p__fmode();
|
|
||||||
int CDECL _crt_atexit(_PVFV func);
|
|
||||||
int CDECL _configure_narrow_argv(_crt_argv_mode mode);
|
|
||||||
_invalid_parameter_handler CDECL _set_invalid_parameter_handler(_invalid_parameter_handler newHandler);
|
|
||||||
int CDECL _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask);
|
|
||||||
int CDECL _configthreadlocale(int per_thread_locale_type);
|
|
||||||
int CDECL _initialize_narrow_environment();
|
|
||||||
int CDECL _set_new_mode(int newhandlermode);
|
|
||||||
GUEST_PTR CDECL _get_initial_narrow_environment();
|
|
||||||
GUEST_PTR CDECL __p__environ();
|
|
||||||
GUEST_PTR CDECL __p___argv();
|
|
||||||
GUEST_PTR CDECL __p___argc();
|
|
||||||
SIZE_T CDECL strlen(const char *str);
|
|
||||||
int CDECL strcmp(const char *lhs, const char *rhs);
|
|
||||||
int CDECL strncmp(const char *lhs, const char *rhs, SIZE_T count);
|
|
||||||
char *CDECL strcpy(char *dest, const char *src);
|
|
||||||
char *CDECL strncpy(char *dest, const char *src, SIZE_T count);
|
|
||||||
const char *CDECL strrchr(const char *str, int ch);
|
|
||||||
void *CDECL malloc(SIZE_T size);
|
|
||||||
void *CDECL calloc(SIZE_T count, SIZE_T size);
|
|
||||||
void *CDECL realloc(void *ptr, SIZE_T newSize);
|
|
||||||
void CDECL free(void *ptr);
|
|
||||||
void *CDECL memcpy(void *dest, const void *src, SIZE_T count);
|
|
||||||
void *CDECL memmove(void *dest, const void *src, SIZE_T count);
|
|
||||||
void *CDECL memset(void *dest, int ch, SIZE_T count);
|
|
||||||
int CDECL memcmp(const void *lhs, const void *rhs, SIZE_T count);
|
|
||||||
int CDECL __setusermatherr(void *handler);
|
|
||||||
int CDECL _initialize_onexit_table(_onexit_table_t *table);
|
|
||||||
int CDECL _register_onexit_function(_onexit_table_t *table, _onexit_t func);
|
|
||||||
int CDECL _execute_onexit_table(_onexit_table_t *table);
|
|
||||||
void CDECL exit(int status);
|
|
||||||
void CDECL _cexit();
|
|
||||||
void CDECL _exit(int status);
|
|
||||||
void CDECL abort();
|
|
||||||
signal_handler CDECL signal(int signum, signal_handler handler);
|
|
||||||
void *CDECL __acrt_iob_func(unsigned int index);
|
|
||||||
#ifndef __x86_64__ // TODO
|
|
||||||
int CDECL_NO_CONV __stdio_common_vfprintf(ULONGLONG options, _FILE *stream, const char *format, void *locale,
|
|
||||||
va_list args);
|
|
||||||
int CDECL_NO_CONV __stdio_common_vsprintf(ULONGLONG options, char *buffer, SIZE_T len, const char *format,
|
|
||||||
void *locale, va_list args);
|
|
||||||
#endif
|
|
||||||
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare);
|
|
||||||
int CDECL puts(const char *str);
|
|
||||||
|
|
||||||
} // namespace crt
|
|
||||||
@@ -39,7 +39,7 @@ BOOL WINAPI DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, H
|
|||||||
|
|
||||||
auto &handles = wibo::handles();
|
auto &handles = wibo::handles();
|
||||||
if (isPseudoCurrentProcessHandle(hSourceHandle)) {
|
if (isPseudoCurrentProcessHandle(hSourceHandle)) {
|
||||||
auto po = make_pin<ProcessObject>(getpid(), -1);
|
auto po = make_pin<ProcessObject>(getpid(), -1, false);
|
||||||
auto handle = handles.alloc(std::move(po), 0, 0);
|
auto handle = handles.alloc(std::move(po), 0, 0);
|
||||||
DEBUG_LOG("DuplicateHandle: created process handle for current process -> %p\n", handle);
|
DEBUG_LOG("DuplicateHandle: created process handle for current process -> %p\n", handle);
|
||||||
*lpTargetHandle = handle;
|
*lpTargetHandle = handle;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
namespace kernel32 {
|
namespace kernel32 {
|
||||||
@@ -11,22 +10,22 @@ namespace kernel32 {
|
|||||||
LONG WINAPI InterlockedIncrement(LONG volatile *Addend) {
|
LONG WINAPI InterlockedIncrement(LONG volatile *Addend) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("InterlockedIncrement(%p)\n", Addend);
|
VERBOSE_LOG("InterlockedIncrement(%p)\n", Addend);
|
||||||
std::atomic_ref<LONG> a(*const_cast<LONG *>(Addend));
|
auto *ptr = const_cast<LONG *>(Addend);
|
||||||
return a.fetch_add(1, std::memory_order_seq_cst) + 1;
|
return __atomic_add_fetch(ptr, 1, __ATOMIC_SEQ_CST);
|
||||||
}
|
}
|
||||||
|
|
||||||
LONG WINAPI InterlockedDecrement(LONG volatile *Addend) {
|
LONG WINAPI InterlockedDecrement(LONG volatile *Addend) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("InterlockedDecrement(%p)\n", Addend);
|
VERBOSE_LOG("InterlockedDecrement(%p)\n", Addend);
|
||||||
std::atomic_ref<LONG> a(*const_cast<LONG *>(Addend));
|
auto *ptr = const_cast<LONG *>(Addend);
|
||||||
return a.fetch_sub(1, std::memory_order_seq_cst) - 1;
|
return __atomic_sub_fetch(ptr, 1, __ATOMIC_SEQ_CST);
|
||||||
}
|
}
|
||||||
|
|
||||||
LONG WINAPI InterlockedExchange(LONG volatile *Target, LONG Value) {
|
LONG WINAPI InterlockedExchange(LONG volatile *Target, LONG Value) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("InterlockedExchange(%p, %ld)\n", Target, static_cast<long>(Value));
|
VERBOSE_LOG("InterlockedExchange(%p, %ld)\n", Target, static_cast<long>(Value));
|
||||||
std::atomic_ref<LONG> a(*const_cast<LONG *>(Target));
|
auto *ptr = const_cast<LONG *>(Target);
|
||||||
return a.exchange(Value, std::memory_order_seq_cst);
|
return __atomic_exchange_n(ptr, Value, __ATOMIC_SEQ_CST);
|
||||||
}
|
}
|
||||||
|
|
||||||
LONG WINAPI InterlockedCompareExchange(LONG volatile *Destination, LONG Exchange, LONG Comperand) {
|
LONG WINAPI InterlockedCompareExchange(LONG volatile *Destination, LONG Exchange, LONG Comperand) {
|
||||||
@@ -34,9 +33,9 @@ LONG WINAPI InterlockedCompareExchange(LONG volatile *Destination, LONG Exchange
|
|||||||
VERBOSE_LOG("InterlockedCompareExchange(%p, %ld, %ld)\n", Destination, static_cast<long>(Exchange),
|
VERBOSE_LOG("InterlockedCompareExchange(%p, %ld, %ld)\n", Destination, static_cast<long>(Exchange),
|
||||||
static_cast<long>(Comperand));
|
static_cast<long>(Comperand));
|
||||||
|
|
||||||
std::atomic_ref<LONG> a(*const_cast<LONG *>(Destination));
|
auto *ptr = const_cast<LONG *>(Destination);
|
||||||
LONG expected = Comperand;
|
LONG expected = Comperand;
|
||||||
a.compare_exchange_strong(expected, Exchange, std::memory_order_seq_cst);
|
__atomic_compare_exchange_n(ptr, &expected, Exchange, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||||
return expected;
|
return expected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -64,8 +64,10 @@ struct ProcessObject final : WaitableObject {
|
|||||||
int pidfd;
|
int pidfd;
|
||||||
DWORD exitCode = STILL_ACTIVE;
|
DWORD exitCode = STILL_ACTIVE;
|
||||||
bool forcedExitCode = false;
|
bool forcedExitCode = false;
|
||||||
|
bool waitable = true;
|
||||||
|
|
||||||
explicit ProcessObject(pid_t pid, int pidfd) : WaitableObject(kType), pid(pid), pidfd(pidfd) {}
|
explicit ProcessObject(pid_t pid, int pidfd, bool waitable = true)
|
||||||
|
: WaitableObject(kType), pid(pid), pidfd(pidfd), waitable(waitable) {}
|
||||||
|
|
||||||
~ProcessObject() override {
|
~ProcessObject() override {
|
||||||
if (pidfd != -1) {
|
if (pidfd != -1) {
|
||||||
@@ -75,6 +77,12 @@ struct ProcessObject final : WaitableObject {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
constexpr pthread_t pthread_null = 0;
|
||||||
|
#else
|
||||||
|
constexpr pthread_t pthread_null = nullptr;
|
||||||
|
#endif
|
||||||
|
|
||||||
struct ThreadObject final : WaitableObject {
|
struct ThreadObject final : WaitableObject {
|
||||||
static constexpr ObjectType kType = ObjectType::Thread;
|
static constexpr ObjectType kType = ObjectType::Thread;
|
||||||
|
|
||||||
@@ -83,7 +91,7 @@ struct ThreadObject final : WaitableObject {
|
|||||||
unsigned int suspendCount = 0;
|
unsigned int suspendCount = 0;
|
||||||
TEB *tib = nullptr;
|
TEB *tib = nullptr;
|
||||||
|
|
||||||
explicit ThreadObject(pthread_t thread) : WaitableObject(kType), thread(thread) {}
|
explicit ThreadObject(pthread_t thread = pthread_null) : WaitableObject(kType), thread(thread) {}
|
||||||
|
|
||||||
~ThreadObject() override {
|
~ThreadObject() override {
|
||||||
// Threads are detached at creation; we can safely drop
|
// Threads are detached at creation; we can safely drop
|
||||||
|
|||||||
@@ -368,11 +368,13 @@ BOOL WINAPI CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBU
|
|||||||
configureInheritability(pipeFds[0], inheritHandles);
|
configureInheritability(pipeFds[0], inheritHandles);
|
||||||
configureInheritability(pipeFds[1], inheritHandles);
|
configureInheritability(pipeFds[1], inheritHandles);
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
if (nSize != 0) {
|
if (nSize != 0) {
|
||||||
// Best-effort adjustment; ignore failures as recommended by docs.
|
// Best-effort adjustment; ignore failures as recommended by docs.
|
||||||
fcntl(pipeFds[0], F_SETPIPE_SZ, static_cast<int>(nSize));
|
fcntl(pipeFds[0], F_SETPIPE_SZ, static_cast<int>(nSize));
|
||||||
fcntl(pipeFds[1], F_SETPIPE_SZ, static_cast<int>(nSize));
|
fcntl(pipeFds[1], F_SETPIPE_SZ, static_cast<int>(nSize));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
auto readObj = make_pin<FileObject>(pipeFds[0]);
|
auto readObj = make_pin<FileObject>(pipeFds[0]);
|
||||||
readObj->shareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
readObj->shareAccess = FILE_SHARE_READ | FILE_SHARE_WRITE;
|
||||||
@@ -384,8 +386,8 @@ BOOL WINAPI CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBU
|
|||||||
}
|
}
|
||||||
|
|
||||||
HANDLE WINAPI CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
|
HANDLE WINAPI CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode, DWORD nMaxInstances,
|
||||||
DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut,
|
DWORD nOutBufferSize, DWORD nInBufferSize, DWORD nDefaultTimeOut,
|
||||||
LPSECURITY_ATTRIBUTES lpSecurityAttributes) {
|
LPSECURITY_ATTRIBUTES lpSecurityAttributes) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("CreateNamedPipeA(%s, 0x%08x, 0x%08x, %u, %u, %u, %u, %p)\n", lpName ? lpName : "(null)", dwOpenMode,
|
DEBUG_LOG("CreateNamedPipeA(%s, 0x%08x, 0x%08x, %u, %u, %u, %u, %p)\n", lpName ? lpName : "(null)", dwOpenMode,
|
||||||
dwPipeMode, nMaxInstances, nOutBufferSize, nInBufferSize, nDefaultTimeOut, lpSecurityAttributes);
|
dwPipeMode, nMaxInstances, nOutBufferSize, nInBufferSize, nDefaultTimeOut, lpSecurityAttributes);
|
||||||
@@ -479,15 +481,19 @@ HANDLE WINAPI CreateNamedPipeA(LPCSTR lpName, DWORD dwOpenMode, DWORD dwPipeMode
|
|||||||
if (accessMode == PIPE_ACCESS_INBOUND) {
|
if (accessMode == PIPE_ACCESS_INBOUND) {
|
||||||
serverFd = fds[0];
|
serverFd = fds[0];
|
||||||
companionFd = fds[1];
|
companionFd = fds[1];
|
||||||
|
#ifdef __linux__
|
||||||
if (nInBufferSize != 0) {
|
if (nInBufferSize != 0) {
|
||||||
fcntl(serverFd, F_SETPIPE_SZ, static_cast<int>(nInBufferSize));
|
fcntl(serverFd, F_SETPIPE_SZ, static_cast<int>(nInBufferSize));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
serverFd = fds[1];
|
serverFd = fds[1];
|
||||||
companionFd = fds[0];
|
companionFd = fds[0];
|
||||||
|
#ifdef __linux__
|
||||||
if (nOutBufferSize != 0) {
|
if (nOutBufferSize != 0) {
|
||||||
fcntl(serverFd, F_SETPIPE_SZ, static_cast<int>(nOutBufferSize));
|
fcntl(serverFd, F_SETPIPE_SZ, static_cast<int>(nOutBufferSize));
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,10 @@
|
|||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
extern char **environ;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
GUEST_PTR g_commandLineA = GUEST_NULL;
|
GUEST_PTR g_commandLineA = GUEST_NULL;
|
||||||
|
|||||||
@@ -196,7 +196,11 @@ DWORD WINAPI GetCurrentProcessId() {
|
|||||||
DWORD WINAPI GetCurrentThreadId() {
|
DWORD WINAPI GetCurrentThreadId() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
pthread_t thread = pthread_self();
|
pthread_t thread = pthread_self();
|
||||||
|
#ifdef __linux__
|
||||||
const auto threadId = static_cast<DWORD>(thread);
|
const auto threadId = static_cast<DWORD>(thread);
|
||||||
|
#else
|
||||||
|
const auto threadId = static_cast<DWORD>(reinterpret_cast<uintptr_t>(thread));
|
||||||
|
#endif
|
||||||
DEBUG_LOG("GetCurrentThreadId() -> %u\n", threadId);
|
DEBUG_LOG("GetCurrentThreadId() -> %u\n", threadId);
|
||||||
return threadId;
|
return threadId;
|
||||||
}
|
}
|
||||||
@@ -322,10 +326,25 @@ BOOL WINAPI TerminateProcess(HANDLE hProcess, UINT uExitCode) {
|
|||||||
if (process->signaled) {
|
if (process->signaled) {
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
if (syscall(SYS_pidfd_send_signal, process->pidfd, SIGKILL, nullptr, 0) != 0) {
|
int killResult = 0;
|
||||||
int err = errno;
|
#if defined(__linux__)
|
||||||
DEBUG_LOG("TerminateProcess: pidfd_send_signal(%d) failed: %s\n", process->pidfd, strerror(err));
|
if (process->pidfd != -1) {
|
||||||
switch (err) {
|
if (syscall(SYS_pidfd_send_signal, process->pidfd, SIGKILL, nullptr, 0) != 0) {
|
||||||
|
killResult = errno;
|
||||||
|
DEBUG_LOG("TerminateProcess: pidfd_send_signal(%d) failed: %s\n", process->pidfd, strerror(killResult));
|
||||||
|
}
|
||||||
|
} else if (kill(process->pid, SIGKILL) != 0) {
|
||||||
|
killResult = errno;
|
||||||
|
DEBUG_LOG("TerminateProcess: kill(%d) failed: %s\n", process->pid, strerror(killResult));
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (kill(process->pid, SIGKILL) != 0) {
|
||||||
|
killResult = errno;
|
||||||
|
DEBUG_LOG("TerminateProcess: kill(%d) failed: %s\n", process->pid, strerror(killResult));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (killResult != 0) {
|
||||||
|
switch (killResult) {
|
||||||
case ESRCH:
|
case ESRCH:
|
||||||
case EPERM:
|
case EPERM:
|
||||||
setLastError(ERROR_ACCESS_DENIED);
|
setLastError(ERROR_ACCESS_DENIED);
|
||||||
@@ -467,7 +486,7 @@ HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwSt
|
|||||||
return NO_HANDLE;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pin<ThreadObject> obj = make_pin<ThreadObject>(0); // tid set during pthread_create
|
Pin<ThreadObject> obj = make_pin<ThreadObject>(); // tid set during pthread_create
|
||||||
if ((dwCreationFlags & CREATE_SUSPENDED) != 0) {
|
if ((dwCreationFlags & CREATE_SUSPENDED) != 0) {
|
||||||
obj->suspendCount = 1;
|
obj->suspendCount = 1;
|
||||||
}
|
}
|
||||||
@@ -584,14 +603,16 @@ BOOL WINAPI GetThreadTimes(HANDLE hThread, FILETIME *lpCreationTime, FILETIME *l
|
|||||||
lpExitTime->dwHighDateTime = 0;
|
lpExitTime->dwHighDateTime = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct rusage usage{};
|
#ifdef __linux__
|
||||||
|
struct rusage usage {};
|
||||||
if (getrusage(RUSAGE_THREAD, &usage) == 0) {
|
if (getrusage(RUSAGE_THREAD, &usage) == 0) {
|
||||||
*lpKernelTime = fileTimeFromTimeval(usage.ru_stime);
|
*lpKernelTime = fileTimeFromTimeval(usage.ru_stime);
|
||||||
*lpUserTime = fileTimeFromTimeval(usage.ru_utime);
|
*lpUserTime = fileTimeFromTimeval(usage.ru_utime);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
struct timespec cpuTime{};
|
struct timespec cpuTime {};
|
||||||
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &cpuTime) == 0) {
|
if (clock_gettime(CLOCK_THREAD_CPUTIME_ID, &cpuTime) == 0) {
|
||||||
*lpKernelTime = fileTimeFromDuration(0);
|
*lpKernelTime = fileTimeFromDuration(0);
|
||||||
*lpUserTime = fileTimeFromTimespec(cpuTime);
|
*lpUserTime = fileTimeFromTimespec(cpuTime);
|
||||||
|
|||||||
@@ -437,10 +437,13 @@ DWORD WINAPI WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) {
|
|||||||
case ObjectType::Process: {
|
case ObjectType::Process: {
|
||||||
auto po = std::move(obj).downcast<ProcessObject>();
|
auto po = std::move(obj).downcast<ProcessObject>();
|
||||||
std::unique_lock lk(po->m);
|
std::unique_lock lk(po->m);
|
||||||
if (po->pidfd == -1) {
|
if (!po->signaled && !po->waitable) {
|
||||||
// Windows actually allows you to wait on your own process, but why bother?
|
// Windows actually allows you to wait on your own process, but why bother?
|
||||||
return WAIT_TIMEOUT;
|
return WAIT_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
if (po->signaled) {
|
||||||
|
return WAIT_OBJECT_0;
|
||||||
|
}
|
||||||
bool ok = doWait(lk, po->cv, [&] { return po->signaled; });
|
bool ok = doWait(lk, po->cv, [&] { return po->signaled; });
|
||||||
return ok ? WAIT_OBJECT_0 : WAIT_TIMEOUT;
|
return ok ? WAIT_OBJECT_0 : WAIT_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ BOOL WINAPI GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, CONSOLE_SCREEN_BUF
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI WriteConsoleW(HANDLE hConsoleOutput, LPCVOID lpBuffer, DWORD nNumberOfCharsToWrite,
|
BOOL WINAPI WriteConsoleW(HANDLE hConsoleOutput, LPCVOID lpBuffer, DWORD nNumberOfCharsToWrite,
|
||||||
LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved) {
|
LPDWORD lpNumberOfCharsWritten, LPVOID lpReserved) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("WriteConsoleW(%p, %p, %u, %p, %p)\n", hConsoleOutput, lpBuffer, nNumberOfCharsToWrite,
|
DEBUG_LOG("WriteConsoleW(%p, %p, %u, %p, %p)\n", hConsoleOutput, lpBuffer, nNumberOfCharsToWrite,
|
||||||
lpNumberOfCharsWritten, lpReserved);
|
lpNumberOfCharsWritten, lpReserved);
|
||||||
@@ -110,7 +110,7 @@ DWORD WINAPI GetConsoleTitleW(LPWSTR lpConsoleTitle, DWORD nSize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI PeekConsoleInputA(HANDLE hConsoleInput, INPUT_RECORD *lpBuffer, DWORD nLength,
|
BOOL WINAPI PeekConsoleInputA(HANDLE hConsoleInput, INPUT_RECORD *lpBuffer, DWORD nLength,
|
||||||
LPDWORD lpNumberOfEventsRead) {
|
LPDWORD lpNumberOfEventsRead) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("STUB: PeekConsoleInputA(%p, %p, %u)\n", hConsoleInput, lpBuffer, nLength);
|
DEBUG_LOG("STUB: PeekConsoleInputA(%p, %p, %u)\n", hConsoleInput, lpBuffer, nLength);
|
||||||
(void)hConsoleInput;
|
(void)hConsoleInput;
|
||||||
@@ -123,7 +123,7 @@ BOOL WINAPI PeekConsoleInputA(HANDLE hConsoleInput, INPUT_RECORD *lpBuffer, DWOR
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput, INPUT_RECORD *lpBuffer, DWORD nLength,
|
BOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput, INPUT_RECORD *lpBuffer, DWORD nLength,
|
||||||
LPDWORD lpNumberOfEventsRead) {
|
LPDWORD lpNumberOfEventsRead) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("STUB: ReadConsoleInputA(%p, %p, %u)\n", hConsoleInput, lpBuffer, nLength);
|
DEBUG_LOG("STUB: ReadConsoleInputA(%p, %p, %u)\n", hConsoleInput, lpBuffer, nLength);
|
||||||
(void)hConsoleInput;
|
(void)hConsoleInput;
|
||||||
@@ -135,4 +135,11 @@ BOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput, INPUT_RECORD *lpBuffer, DWOR
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI VerifyConsoleIoHandle(HANDLE handle) {
|
||||||
|
HOST_CONTEXT_GUARD();
|
||||||
|
DEBUG_LOG("STUB: VerifyConsoleIoHandle(%p)\n", handle);
|
||||||
|
(void)handle;
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace kernel32
|
} // namespace kernel32
|
||||||
|
|||||||
@@ -42,5 +42,6 @@ BOOL WINAPI PeekConsoleInputA(HANDLE hConsoleInput, INPUT_RECORD *lpBuffer, DWOR
|
|||||||
LPDWORD lpNumberOfEventsRead);
|
LPDWORD lpNumberOfEventsRead);
|
||||||
BOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput, INPUT_RECORD *lpBuffer, DWORD nLength,
|
BOOL WINAPI ReadConsoleInputA(HANDLE hConsoleInput, INPUT_RECORD *lpBuffer, DWORD nLength,
|
||||||
LPDWORD lpNumberOfEventsRead);
|
LPDWORD lpNumberOfEventsRead);
|
||||||
|
BOOL WINAPI VerifyConsoleIoHandle(HANDLE handle);
|
||||||
|
|
||||||
} // namespace kernel32
|
} // namespace kernel32
|
||||||
|
|||||||
3041
dll/msvcrt.cpp
3041
dll/msvcrt.cpp
File diff suppressed because it is too large
Load Diff
240
dll/msvcrt.h
240
dll/msvcrt.h
@@ -1,240 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include "types.h"
|
|
||||||
|
|
||||||
using TIME_T = int;
|
|
||||||
using WINT_T = unsigned short;
|
|
||||||
|
|
||||||
typedef void(_CC_CDECL *_PVFV)();
|
|
||||||
typedef int(_CC_CDECL *_PIFV)();
|
|
||||||
typedef int(_CC_CDECL *_onexit_t)();
|
|
||||||
typedef void(_CC_CDECL *signal_handler)(int);
|
|
||||||
typedef int(_CC_CDECL *sort_compare)(const void *, const void *);
|
|
||||||
|
|
||||||
struct _utimbuf {
|
|
||||||
LONG actime;
|
|
||||||
LONG modtime;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct _timeb {
|
|
||||||
TIME_T time;
|
|
||||||
unsigned short millitm;
|
|
||||||
short timezone;
|
|
||||||
short dstflag;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lconv;
|
|
||||||
|
|
||||||
namespace msvcrt {
|
|
||||||
|
|
||||||
extern int _commode;
|
|
||||||
extern int _fmode;
|
|
||||||
extern GUEST_PTR __initenv;
|
|
||||||
extern GUEST_PTR __winitenv;
|
|
||||||
extern GUEST_PTR _wpgmptr;
|
|
||||||
extern GUEST_PTR _pgmptr;
|
|
||||||
extern int __mb_cur_max;
|
|
||||||
extern _FILE _iob[_IOB_ENTRIES];
|
|
||||||
|
|
||||||
_FILE *CDECL __iob_func();
|
|
||||||
_FILE *CDECL __p__iob();
|
|
||||||
void CDECL setbuf(_FILE *stream, char *buffer);
|
|
||||||
void CDECL _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext);
|
|
||||||
int CDECL _fileno(_FILE *stream);
|
|
||||||
int CDECL _getmbcp();
|
|
||||||
GUEST_PTR CDECL __p___mb_cur_max();
|
|
||||||
int CDECL _setmbcp(int codepage);
|
|
||||||
GUEST_PTR CDECL __p__mbctype();
|
|
||||||
GUEST_PTR CDECL __p__pctype();
|
|
||||||
int CDECL _isctype(int ch, int mask);
|
|
||||||
void CDECL __set_app_type(int at);
|
|
||||||
GUEST_PTR CDECL __p__fmode();
|
|
||||||
GUEST_PTR CDECL __p__commode();
|
|
||||||
void CDECL _initterm(GUEST_PTR *ppfn, GUEST_PTR *end);
|
|
||||||
int CDECL _initterm_e(GUEST_PTR *ppfn, GUEST_PTR *end);
|
|
||||||
unsigned int CDECL _controlfp(unsigned int newControl, unsigned int mask);
|
|
||||||
int CDECL _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask);
|
|
||||||
_onexit_t CDECL _onexit(_onexit_t func);
|
|
||||||
int CDECL __wgetmainargs(int *wargc, GUEST_PTR *wargv, GUEST_PTR *wenv, int doWildcard, int *startInfo);
|
|
||||||
int CDECL __getmainargs(int *argc, GUEST_PTR *argv, GUEST_PTR *env, int doWildcard, int *startInfo);
|
|
||||||
char *CDECL getenv(const char *varname);
|
|
||||||
GUEST_PTR CDECL __p___initenv();
|
|
||||||
char *CDECL strcat(char *dest, const char *src);
|
|
||||||
char *CDECL strcpy(char *dest, const char *src);
|
|
||||||
int CDECL _access(const char *path, int mode);
|
|
||||||
int CDECL _ismbblead(unsigned int c);
|
|
||||||
int CDECL _ismbbtrail(unsigned int c);
|
|
||||||
int CDECL _ismbcspace(unsigned int c);
|
|
||||||
void CDECL _mbccpy(unsigned char *dest, const unsigned char *src);
|
|
||||||
unsigned char *CDECL _mbsinc(const unsigned char *str);
|
|
||||||
unsigned char *CDECL _mbsdec(const unsigned char *start, const unsigned char *current);
|
|
||||||
unsigned int CDECL _mbclen(const unsigned char *str);
|
|
||||||
int CDECL _mbscmp(const unsigned char *lhs, const unsigned char *rhs);
|
|
||||||
int CDECL _mbsicmp(const unsigned char *lhs, const unsigned char *rhs);
|
|
||||||
unsigned char *CDECL _mbsstr(const unsigned char *haystack, const unsigned char *needle);
|
|
||||||
unsigned char *CDECL _mbschr(const unsigned char *str, unsigned int ch);
|
|
||||||
unsigned char *CDECL _mbsrchr(const unsigned char *str, unsigned int ch);
|
|
||||||
unsigned char *CDECL _mbslwr(unsigned char *str);
|
|
||||||
unsigned char *CDECL _mbsupr(unsigned char *str);
|
|
||||||
unsigned char *CDECL _mbsinc_l(const unsigned char *str, void *);
|
|
||||||
unsigned char *CDECL _mbsdec_l(const unsigned char *start, const unsigned char *current, void *locale);
|
|
||||||
int CDECL _mbsncmp(const unsigned char *lhs, const unsigned char *rhs, SIZE_T count);
|
|
||||||
SIZE_T CDECL _mbsspn(const unsigned char *str, const unsigned char *set);
|
|
||||||
int CDECL _ismbcdigit(unsigned int ch);
|
|
||||||
int CDECL _stricmp(const char *lhs, const char *rhs);
|
|
||||||
int CDECL _strnicmp(const char *lhs, const char *rhs, SIZE_T count);
|
|
||||||
int CDECL _memicmp(const void *lhs, const void *rhs, SIZE_T count);
|
|
||||||
#ifndef __x86_64__ // TODO
|
|
||||||
int CDECL_NO_CONV _vsnprintf(char *buffer, SIZE_T count, const char *format, va_list args);
|
|
||||||
int CDECL_NO_CONV _snprintf(char *buffer, SIZE_T count, const char *format, ...);
|
|
||||||
int CDECL_NO_CONV sprintf(char *buffer, const char *format, ...);
|
|
||||||
int CDECL_NO_CONV printf(const char *format, ...);
|
|
||||||
int CDECL_NO_CONV sscanf(const char *buffer, const char *format, ...);
|
|
||||||
#endif
|
|
||||||
char *CDECL fgets(char *str, int count, _FILE *stream);
|
|
||||||
SIZE_T CDECL fread(void *buffer, SIZE_T size, SIZE_T count, _FILE *stream);
|
|
||||||
_FILE *CDECL _fsopen(const char *filename, const char *mode, int shflag);
|
|
||||||
int CDECL _sopen(const char *path, int oflag, int shflag, int pmode);
|
|
||||||
int CDECL _read(int fd, void *buffer, unsigned int count);
|
|
||||||
int CDECL _close(int fd);
|
|
||||||
LONG CDECL _lseek(int fd, LONG offset, int origin);
|
|
||||||
int CDECL _unlink(const char *path);
|
|
||||||
int CDECL _utime(const char *path, const _utimbuf *times);
|
|
||||||
int CDECL _chsize(int fd, LONG size);
|
|
||||||
char *CDECL strncpy(char *dest, const char *src, SIZE_T count);
|
|
||||||
char *CDECL strpbrk(const char *str, const char *accept);
|
|
||||||
char *CDECL strstr(const char *haystack, const char *needle);
|
|
||||||
char *CDECL strrchr(const char *str, int ch);
|
|
||||||
char *CDECL strtok(char *str, const char *delim);
|
|
||||||
LONG CDECL _adj_fdiv_r(LONG value);
|
|
||||||
void CDECL _adjust_fdiv(LONG n);
|
|
||||||
int CDECL _ftime(struct _timeb *timeptr);
|
|
||||||
ULONG CDECL _ultoa(ULONG value, char *str, int radix);
|
|
||||||
char *CDECL _ltoa(LONG value, char *str, int radix);
|
|
||||||
char *CDECL _makepath(char *path, const char *drive, const char *dir, const char *fname, const char *ext);
|
|
||||||
char *CDECL _fullpath(char *absPath, const char *relPath, SIZE_T maxLength);
|
|
||||||
int CDECL _putenv(const char *envString);
|
|
||||||
char *CDECL _mktemp(char *templateName);
|
|
||||||
int CDECL _except_handler3(void *record, void *frame, void *context, void *dispatch);
|
|
||||||
int CDECL getchar();
|
|
||||||
TIME_T CDECL time(TIME_T *t);
|
|
||||||
char *CDECL __unDName(char *outputString, const char *mangledName, int maxStringLength, void *(*allocFunc)(SIZE_T),
|
|
||||||
void (*freeFunc)(void *), unsigned short);
|
|
||||||
char *CDECL setlocale(int category, const char *locale);
|
|
||||||
int CDECL _wdupenv_s(GUEST_PTR *buffer, SIZE_T *numberOfElements, const WCHAR *varname);
|
|
||||||
int CDECL _wgetenv_s(SIZE_T *pReturnValue, WCHAR *buffer, SIZE_T numberOfElements, const WCHAR *varname);
|
|
||||||
SIZE_T CDECL strlen(const char *str);
|
|
||||||
int CDECL strcmp(const char *lhs, const char *rhs);
|
|
||||||
int CDECL strncmp(const char *lhs, const char *rhs, SIZE_T count);
|
|
||||||
void CDECL _exit(int status);
|
|
||||||
int CDECL strcpy_s(char *dest, SIZE_T dest_size, const char *src);
|
|
||||||
int CDECL strcat_s(char *dest, SIZE_T numberOfElements, const char *src);
|
|
||||||
int CDECL strncpy_s(char *dest, SIZE_T dest_size, const char *src, SIZE_T count);
|
|
||||||
char *CDECL _strdup(const char *strSource);
|
|
||||||
ULONG CDECL strtoul(const char *str, GUEST_PTR *endptr, int base);
|
|
||||||
void *CDECL malloc(SIZE_T size);
|
|
||||||
void *CDECL calloc(SIZE_T count, SIZE_T size);
|
|
||||||
void *CDECL realloc(void *ptr, SIZE_T size);
|
|
||||||
void *CDECL _malloc_crt(SIZE_T size);
|
|
||||||
void CDECL _lock(int locknum);
|
|
||||||
void CDECL _unlock(int locknum);
|
|
||||||
_onexit_t CDECL __dllonexit(_onexit_t func, GUEST_PTR *pbegin, GUEST_PTR *pend);
|
|
||||||
void CDECL free(void *ptr);
|
|
||||||
void *CDECL memcpy(void *dest, const void *src, SIZE_T count);
|
|
||||||
void *CDECL memmove(void *dest, const void *src, SIZE_T count);
|
|
||||||
int CDECL memcmp(const void *lhs, const void *rhs, SIZE_T count);
|
|
||||||
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare);
|
|
||||||
int CDECL fflush(_FILE *stream);
|
|
||||||
#ifndef __x86_64__ // TODO
|
|
||||||
int CDECL_NO_CONV vfwprintf(_FILE *stream, const WCHAR *format, va_list args);
|
|
||||||
#endif
|
|
||||||
_FILE *CDECL fopen(const char *filename, const char *mode);
|
|
||||||
int CDECL _dup2(int fd1, int fd2);
|
|
||||||
int CDECL _isatty(int fd);
|
|
||||||
int CDECL fseek(_FILE *stream, LONG offset, int origin);
|
|
||||||
LONG CDECL ftell(_FILE *stream);
|
|
||||||
int CDECL feof(_FILE *stream);
|
|
||||||
int CDECL fputws(const WCHAR *str, _FILE *stream);
|
|
||||||
int CDECL _cputws(const WCHAR *string);
|
|
||||||
WCHAR *CDECL fgetws(WCHAR *buffer, int size, _FILE *stream);
|
|
||||||
WINT_T CDECL fgetwc(_FILE *stream);
|
|
||||||
int CDECL _wfopen_s(GUEST_PTR *stream, const WCHAR *filename, const WCHAR *mode);
|
|
||||||
int CDECL _wcsicmp(const WCHAR *lhs, const WCHAR *rhs);
|
|
||||||
int CDECL _wmakepath_s(WCHAR *path, SIZE_T sizeInWords, const WCHAR *drive, const WCHAR *dir, const WCHAR *fname,
|
|
||||||
const WCHAR *ext);
|
|
||||||
int CDECL _wputenv_s(const WCHAR *varname, const WCHAR *value);
|
|
||||||
ULONG CDECL wcsspn(const WCHAR *str1, const WCHAR *str2);
|
|
||||||
LONG CDECL _wtol(const WCHAR *str);
|
|
||||||
int CDECL _wcsupr_s(WCHAR *str, SIZE_T size);
|
|
||||||
int CDECL _wcslwr_s(WCHAR *str, SIZE_T size);
|
|
||||||
WINT_T CDECL towlower(WINT_T ch);
|
|
||||||
unsigned int CDECL _mbctolower(unsigned int ch);
|
|
||||||
int CDECL toupper(int ch);
|
|
||||||
int CDECL tolower(int ch);
|
|
||||||
int CDECL _ftime64_s(void *timeb);
|
|
||||||
int CDECL _crt_debugger_hook(int value);
|
|
||||||
int CDECL _configthreadlocale(int mode);
|
|
||||||
void CDECL __setusermatherr(void *handler);
|
|
||||||
void CDECL _cexit();
|
|
||||||
#ifndef __x86_64__ // TODO
|
|
||||||
int CDECL_NO_CONV vfprintf(_FILE *stream, const char *format, va_list args);
|
|
||||||
int CDECL_NO_CONV fprintf(_FILE *stream, const char *format, ...);
|
|
||||||
#endif
|
|
||||||
int CDECL fputc(int ch, _FILE *stream);
|
|
||||||
SIZE_T CDECL fwrite(const void *buffer, SIZE_T size, SIZE_T count, _FILE *stream);
|
|
||||||
char *CDECL strerror(int errnum);
|
|
||||||
char *CDECL strchr(const char *str, int character);
|
|
||||||
struct lconv *CDECL localeconv();
|
|
||||||
signal_handler CDECL signal(int sig, signal_handler handler);
|
|
||||||
SIZE_T CDECL wcslen(const WCHAR *str);
|
|
||||||
void CDECL abort();
|
|
||||||
int CDECL atoi(const char *str);
|
|
||||||
int CDECL _amsg_exit(int reason);
|
|
||||||
void CDECL _invoke_watson(const WCHAR *, const WCHAR *, const WCHAR *, UINT, UINT_PTR);
|
|
||||||
void CDECL terminateShim();
|
|
||||||
int CDECL _purecall();
|
|
||||||
int CDECL _except_handler4_common(void *, void *, void *, void *);
|
|
||||||
LONG CDECL _XcptFilter(ULONG code, void *);
|
|
||||||
int CDECL _get_wpgmptr(GUEST_PTR *pValue);
|
|
||||||
GUEST_PTR CDECL __p__pgmptr();
|
|
||||||
int CDECL _wsplitpath_s(const WCHAR *path, WCHAR *drive, SIZE_T driveNumberOfElements, WCHAR *dir,
|
|
||||||
SIZE_T dirNumberOfElements, WCHAR *fname, SIZE_T nameNumberOfElements, WCHAR *ext,
|
|
||||||
SIZE_T extNumberOfElements);
|
|
||||||
int CDECL wcscat_s(WCHAR *strDestination, SIZE_T numberOfElements, const WCHAR *strSource);
|
|
||||||
WCHAR *CDECL _wcsdup(const WCHAR *strSource);
|
|
||||||
int CDECL _waccess_s(const WCHAR *path, int mode);
|
|
||||||
void *CDECL memset(void *s, int c, SIZE_T n);
|
|
||||||
int CDECL wcsncpy_s(WCHAR *strDest, SIZE_T numberOfElements, const WCHAR *strSource, SIZE_T count);
|
|
||||||
int CDECL wcsncat_s(WCHAR *strDest, SIZE_T numberOfElements, const WCHAR *strSource, SIZE_T count);
|
|
||||||
int CDECL _itow_s(int value, WCHAR *buffer, SIZE_T size, int radix);
|
|
||||||
int CDECL _wtoi(const WCHAR *str);
|
|
||||||
int CDECL _ltoa_s(LONG value, char *buffer, SIZE_T sizeInChars, int radix);
|
|
||||||
int CDECL wcscpy_s(WCHAR *dest, SIZE_T dest_size, const WCHAR *src);
|
|
||||||
#ifndef __x86_64__ // TODO
|
|
||||||
int CDECL_NO_CONV swprintf_s(WCHAR *buffer, SIZE_T sizeOfBuffer, const WCHAR *format, ...);
|
|
||||||
int CDECL_NO_CONV swscanf_s(const WCHAR *buffer, const WCHAR *format, ...);
|
|
||||||
#endif
|
|
||||||
int *CDECL _get_osfhandle(int fd);
|
|
||||||
int CDECL _write(int fd, const void *buffer, unsigned int count);
|
|
||||||
void CDECL exit(int status);
|
|
||||||
int CDECL wcsncmp(const WCHAR *string1, const WCHAR *string2, SIZE_T count);
|
|
||||||
#ifndef __x86_64__ // TODO
|
|
||||||
int CDECL_NO_CONV _vswprintf_c_l(WCHAR *buffer, SIZE_T size, const WCHAR *format, ...);
|
|
||||||
#endif
|
|
||||||
const WCHAR *CDECL wcsstr(const WCHAR *dest, const WCHAR *src);
|
|
||||||
int CDECL iswspace(WINT_T w);
|
|
||||||
int CDECL iswdigit(WINT_T w);
|
|
||||||
const WCHAR *CDECL wcschr(const WCHAR *str, WCHAR c);
|
|
||||||
const WCHAR *CDECL wcsrchr(const WCHAR *str, WCHAR c);
|
|
||||||
ULONG CDECL wcstoul(const WCHAR *strSource, GUEST_PTR *endptr, int base);
|
|
||||||
_FILE *CDECL _wfsopen(const WCHAR *filename, const WCHAR *mode, int shflag);
|
|
||||||
int CDECL puts(const char *str);
|
|
||||||
int CDECL fclose(_FILE *stream);
|
|
||||||
int CDECL _flushall();
|
|
||||||
int *CDECL _errno();
|
|
||||||
LONG_PTR CDECL _wspawnvp(int mode, const WCHAR *cmdname, GUEST_PTR *argv);
|
|
||||||
LONG_PTR CDECL _spawnvp(int mode, const char *cmdname, GUEST_PTR *argv);
|
|
||||||
int CDECL _wunlink(const WCHAR *filename);
|
|
||||||
WCHAR *CDECL _wfullpath(WCHAR *absPath, const WCHAR *relPath, SIZE_T maxLength);
|
|
||||||
|
|
||||||
} // namespace msvcrt
|
|
||||||
@@ -49,7 +49,9 @@ static constexpr BackendEntry kBackends[] = {
|
|||||||
#if WIBO_ENABLE_LIBURING
|
#if WIBO_ENABLE_LIBURING
|
||||||
{"io_uring", detail::createIoUringBackend},
|
{"io_uring", detail::createIoUringBackend},
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef __linux__
|
||||||
{"epoll", detail::createEpollBackend},
|
{"epoll", detail::createEpollBackend},
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
AsyncIOBackend &asyncIO() {
|
AsyncIOBackend &asyncIO() {
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ namespace detail {
|
|||||||
#if WIBO_ENABLE_LIBURING
|
#if WIBO_ENABLE_LIBURING
|
||||||
std::unique_ptr<AsyncIOBackend> createIoUringBackend();
|
std::unique_ptr<AsyncIOBackend> createIoUringBackend();
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef __linux__
|
||||||
std::unique_ptr<AsyncIOBackend> createEpollBackend();
|
std::unique_ptr<AsyncIOBackend> createEpollBackend();
|
||||||
|
#endif
|
||||||
|
|
||||||
} // namespace detail
|
} // namespace detail
|
||||||
|
|
||||||
|
|||||||
39
src/heap.cpp
39
src/heap.cpp
@@ -17,15 +17,17 @@
|
|||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
// Alpine hack: rename duplicate prctl_mm_map (sys/prctl.h also includes it)
|
// Alpine hack: rename duplicate prctl_mm_map (sys/prctl.h also includes it)
|
||||||
#define prctl_mm_map _prctl_mm_map
|
#define prctl_mm_map _prctl_mm_map
|
||||||
#include <linux/prctl.h>
|
#include <linux/prctl.h>
|
||||||
#undef prctl_mm_map
|
#undef prctl_mm_map
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <mimalloc.h>
|
#include <mimalloc.h>
|
||||||
#include <mimalloc/internal.h>
|
#include <mimalloc/internal.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/prctl.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
// Pre-initialization logging macros
|
// Pre-initialization logging macros
|
||||||
@@ -36,8 +38,14 @@ namespace {
|
|||||||
|
|
||||||
constexpr uintptr_t kLowMemoryStart = 0x00110000UL; // 1 MiB + 64 KiB
|
constexpr uintptr_t kLowMemoryStart = 0x00110000UL; // 1 MiB + 64 KiB
|
||||||
constexpr uintptr_t kHeapMax = 0x60000000UL; // 1 GiB
|
constexpr uintptr_t kHeapMax = 0x60000000UL; // 1 GiB
|
||||||
|
#ifdef __APPLE__
|
||||||
|
// On macOS, our program is mapped at 0x7E001000
|
||||||
|
constexpr uintptr_t kTopDownStart = 0x7D000000UL;
|
||||||
|
constexpr uintptr_t kTwoGB = 0x7E000000UL;
|
||||||
|
#else
|
||||||
constexpr uintptr_t kTopDownStart = 0x7F000000UL; // Just below 2GB
|
constexpr uintptr_t kTopDownStart = 0x7F000000UL; // Just below 2GB
|
||||||
constexpr uintptr_t kTwoGB = 0x80000000UL;
|
constexpr uintptr_t kTwoGB = 0x80000000UL;
|
||||||
|
#endif
|
||||||
constexpr std::size_t kGuestArenaSize = 512ULL * 1024ULL * 1024ULL; // 512 MiB
|
constexpr std::size_t kGuestArenaSize = 512ULL * 1024ULL * 1024ULL; // 512 MiB
|
||||||
constexpr std::size_t kVirtualAllocationGranularity = 64ULL * 1024ULL;
|
constexpr std::size_t kVirtualAllocationGranularity = 64ULL * 1024ULL;
|
||||||
|
|
||||||
@@ -69,6 +77,7 @@ struct VirtualAllocation {
|
|||||||
|
|
||||||
std::map<uintptr_t, VirtualAllocation> g_virtualAllocations;
|
std::map<uintptr_t, VirtualAllocation> g_virtualAllocations;
|
||||||
|
|
||||||
|
#ifndef __APPLE__
|
||||||
const uintptr_t kDefaultMmapMinAddr = 0x10000u;
|
const uintptr_t kDefaultMmapMinAddr = 0x10000u;
|
||||||
|
|
||||||
uintptr_t readMmapMinAddr() {
|
uintptr_t readMmapMinAddr() {
|
||||||
@@ -98,6 +107,7 @@ uintptr_t mmapMinAddr() {
|
|||||||
static uintptr_t minAddr = readMmapMinAddr();
|
static uintptr_t minAddr = readMmapMinAddr();
|
||||||
return minAddr;
|
return minAddr;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
uintptr_t alignDown(uintptr_t value, std::size_t alignment) {
|
uintptr_t alignDown(uintptr_t value, std::size_t alignment) {
|
||||||
const uintptr_t mask = static_cast<uintptr_t>(alignment) - 1;
|
const uintptr_t mask = static_cast<uintptr_t>(alignment) - 1;
|
||||||
@@ -311,9 +321,13 @@ bool mapAtAddr(uintptr_t addr, std::size_t size, const char *name, void **outPtr
|
|||||||
if (p == MAP_FAILED) {
|
if (p == MAP_FAILED) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
#ifdef __linux__
|
||||||
if (name) {
|
if (name) {
|
||||||
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, size, name);
|
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, addr, size, name);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
(void)name;
|
||||||
|
#endif
|
||||||
recordGuestMapping(addr, size, PAGE_READWRITE, MEM_RESERVE, PAGE_READWRITE, MEM_PRIVATE);
|
recordGuestMapping(addr, size, PAGE_READWRITE, MEM_RESERVE, PAGE_READWRITE, MEM_PRIVATE);
|
||||||
if (outPtr) {
|
if (outPtr) {
|
||||||
*outPtr = p;
|
*outPtr = p;
|
||||||
@@ -668,11 +682,13 @@ VmStatus virtualAlloc(void **baseAddress, std::size_t *regionSize, DWORD allocat
|
|||||||
if (mapped == MAP_FAILED) {
|
if (mapped == MAP_FAILED) {
|
||||||
return vmStatusFromErrno(errno);
|
return vmStatusFromErrno(errno);
|
||||||
}
|
}
|
||||||
|
#ifdef __linux__
|
||||||
if (type == MEM_IMAGE) {
|
if (type == MEM_IMAGE) {
|
||||||
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, base, length, "wibo guest image");
|
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, base, length, "wibo guest image");
|
||||||
} else {
|
} else {
|
||||||
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, base, length, "wibo guest allocated");
|
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, base, length, "wibo guest allocated");
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
uintptr_t actualBase = reinterpret_cast<uintptr_t>(mapped);
|
uintptr_t actualBase = reinterpret_cast<uintptr_t>(mapped);
|
||||||
VirtualAllocation allocation{};
|
VirtualAllocation allocation{};
|
||||||
allocation.base = actualBase;
|
allocation.base = actualBase;
|
||||||
@@ -739,7 +755,9 @@ VmStatus virtualAlloc(void **baseAddress, std::size_t *regionSize, DWORD allocat
|
|||||||
if (res == MAP_FAILED) {
|
if (res == MAP_FAILED) {
|
||||||
return vmStatusFromErrno(errno);
|
return vmStatusFromErrno(errno);
|
||||||
}
|
}
|
||||||
|
#ifdef __linux__
|
||||||
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, run.first, run.second, "wibo guest committed");
|
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, run.first, run.second, "wibo guest committed");
|
||||||
|
#endif
|
||||||
markCommitted(*region, run.first, run.second, protect);
|
markCommitted(*region, run.first, run.second, protect);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -791,7 +809,9 @@ VmStatus virtualFree(void *baseAddress, std::size_t regionSize, DWORD freeType)
|
|||||||
if (res == MAP_FAILED) {
|
if (res == MAP_FAILED) {
|
||||||
return vmStatusFromErrno(errno);
|
return vmStatusFromErrno(errno);
|
||||||
}
|
}
|
||||||
|
#ifdef __linux__
|
||||||
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, base, length, "wibo reserved");
|
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, base, length, "wibo reserved");
|
||||||
|
#endif
|
||||||
eraseGuestMapping(base);
|
eraseGuestMapping(base);
|
||||||
return VmStatus::Success;
|
return VmStatus::Success;
|
||||||
}
|
}
|
||||||
@@ -828,7 +848,9 @@ VmStatus virtualFree(void *baseAddress, std::size_t regionSize, DWORD freeType)
|
|||||||
if (res == MAP_FAILED) {
|
if (res == MAP_FAILED) {
|
||||||
return vmStatusFromErrno(errno);
|
return vmStatusFromErrno(errno);
|
||||||
}
|
}
|
||||||
|
#ifdef __linux__
|
||||||
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, res, length, "wibo reserved");
|
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, res, length, "wibo reserved");
|
||||||
|
#endif
|
||||||
markDecommitted(region, start, length);
|
markDecommitted(region, start, length);
|
||||||
refreshGuestMapping(region);
|
refreshGuestMapping(region);
|
||||||
return VmStatus::Success;
|
return VmStatus::Success;
|
||||||
@@ -1043,6 +1065,7 @@ bool reserveGuestStack(std::size_t stackSizeBytes, void **outStackLimit, void **
|
|||||||
|
|
||||||
} // namespace wibo::heap
|
} // namespace wibo::heap
|
||||||
|
|
||||||
|
#ifndef __APPLE__
|
||||||
static void debugPrintMaps() {
|
static void debugPrintMaps() {
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
int fd = open("/proc/self/maps", O_RDONLY);
|
int fd = open("/proc/self/maps", O_RDONLY);
|
||||||
@@ -1194,7 +1217,9 @@ static size_t blockLower2GB(MEMORY_BASIC_INFORMATION mappings[MAX_NUM_MAPPINGS])
|
|||||||
perror("heap: failed reserve memory");
|
perror("heap: failed reserve memory");
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
#ifdef __linux__
|
||||||
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, len, "wibo reserved");
|
prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, ptr, len, "wibo reserved");
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
lastMapEnd = mapEnd;
|
lastMapEnd = mapEnd;
|
||||||
@@ -1203,27 +1228,36 @@ static size_t blockLower2GB(MEMORY_BASIC_INFORMATION mappings[MAX_NUM_MAPPINGS])
|
|||||||
|
|
||||||
return numMappings;
|
return numMappings;
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__clang__)
|
#if defined(__clang__)
|
||||||
__attribute__((constructor(101)))
|
__attribute__((constructor(101)))
|
||||||
#else
|
#else
|
||||||
__attribute__((constructor))
|
__attribute__((constructor))
|
||||||
#endif
|
#endif
|
||||||
__attribute__((used)) static void wibo_heap_constructor() {
|
__attribute__((used)) static void
|
||||||
|
wibo_heap_constructor() {
|
||||||
|
#ifndef __APPLE__
|
||||||
MEMORY_BASIC_INFORMATION mappings[MAX_NUM_MAPPINGS];
|
MEMORY_BASIC_INFORMATION mappings[MAX_NUM_MAPPINGS];
|
||||||
memset(mappings, 0, sizeof(mappings));
|
memset(mappings, 0, sizeof(mappings));
|
||||||
|
#endif
|
||||||
bool debug = getenv("WIBO_DEBUG_HEAP") != nullptr;
|
bool debug = getenv("WIBO_DEBUG_HEAP") != nullptr;
|
||||||
if (debug) {
|
if (debug) {
|
||||||
LOG_OUT("heap: initializing...\n");
|
LOG_OUT("heap: initializing...\n");
|
||||||
|
#ifndef __APPLE__
|
||||||
debugPrintMaps();
|
debugPrintMaps();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
#ifndef __APPLE__
|
||||||
size_t numMappings = blockLower2GB(mappings);
|
size_t numMappings = blockLower2GB(mappings);
|
||||||
|
#endif
|
||||||
// Now we can allocate memory
|
// Now we can allocate memory
|
||||||
if (debug) {
|
if (debug) {
|
||||||
mi_option_enable(mi_option_show_stats);
|
mi_option_enable(mi_option_show_stats);
|
||||||
mi_option_enable(mi_option_verbose);
|
mi_option_enable(mi_option_verbose);
|
||||||
}
|
}
|
||||||
g_mappings = new std::map<uintptr_t, MEMORY_BASIC_INFORMATION>;
|
g_mappings = new std::map<uintptr_t, MEMORY_BASIC_INFORMATION>;
|
||||||
|
#ifndef __APPLE__
|
||||||
for (size_t i = 0; i < numMappings; ++i) {
|
for (size_t i = 0; i < numMappings; ++i) {
|
||||||
if (debug) {
|
if (debug) {
|
||||||
fprintf(stderr, "Existing %zu: BaseAddress=%x, RegionSize=%u\n", i, mappings[i].BaseAddress,
|
fprintf(stderr, "Existing %zu: BaseAddress=%x, RegionSize=%u\n", i, mappings[i].BaseAddress,
|
||||||
@@ -1231,4 +1265,5 @@ __attribute__((used)) static void wibo_heap_constructor() {
|
|||||||
}
|
}
|
||||||
g_mappings->emplace(reinterpret_cast<uintptr_t>(fromGuestPtr(mappings[i].BaseAddress)), mappings[i]);
|
g_mappings->emplace(reinterpret_cast<uintptr_t>(fromGuestPtr(mappings[i].BaseAddress)), mappings[i]);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
44
src/macros.S
44
src/macros.S
@@ -13,22 +13,42 @@
|
|||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
|
|
||||||
.equ TEB_SP, 0xfa0 # CurrentStackPointer
|
.equ TEB_SP, 0xfa0 # CurrentStackPointer
|
||||||
.equ TEB_FSBASE, 0xfa8 # CurrentFsBase
|
.equ TEB_FSBASE, 0xfa8 # HostFsBase
|
||||||
|
.equ TEB_GSBASE, 0xfb0 # HostGsBase
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
.equ CS_32, 0x23 # 32-bit code segment (Linux)
|
.equ CS_32, 0x23 # 32-bit code segment (Linux)
|
||||||
.equ CS_64, 0x33 # 64-bit code segment (Linux)
|
.equ CS_64, 0x33 # 64-bit code segment (Linux)
|
||||||
.equ DS_32, 0x2b # 32-bit data segment (Linux)
|
.equ DS_32, 0x2b # 32-bit data segment (Linux)
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
.equ CS_64, 0x2b # 64-bit code segment (macOS)
|
||||||
|
#else
|
||||||
|
#error "Unsupported platform"
|
||||||
|
#endif
|
||||||
|
|
||||||
.macro LJMP32
|
.macro LJMP32 teb_reg
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#define m1632 m1632_\@
|
||||||
|
.data
|
||||||
|
m1632:
|
||||||
|
.long 1f # 32-bit code offset
|
||||||
|
.long 0 # 32-bit code segment (filled in at runtime)
|
||||||
|
.text
|
||||||
|
mov r10w, word ptr [\teb_reg+TEB_FS_SEL]
|
||||||
|
sub r10w, 16
|
||||||
|
mov word ptr [rip+m1632+4], r10w
|
||||||
|
jmp fword ptr [rip+m1632]
|
||||||
|
#else
|
||||||
jmp fword ptr [rip] # far jump into 32-bit code
|
jmp fword ptr [rip] # far jump into 32-bit code
|
||||||
.long 1f # 32-bit code offset
|
.long 1f # 32-bit code offset
|
||||||
.word CS_32 # 32-bit code segment (Linux)
|
.word CS_32 # 32-bit code segment
|
||||||
|
#endif
|
||||||
.code32
|
.code32
|
||||||
1:
|
1:
|
||||||
endbr32
|
endbr32
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.macro LJMP64
|
.macro LJMP64 teb_reg
|
||||||
// Annoyingly, we can't assemble this in Intel syntax
|
// Annoyingly, we can't assemble this in Intel syntax
|
||||||
.att_syntax prefix
|
.att_syntax prefix
|
||||||
ljmp $CS_64, $1f
|
ljmp $CS_64, $1f
|
||||||
@@ -39,3 +59,19 @@
|
|||||||
.endm
|
.endm
|
||||||
|
|
||||||
#endif // __x86_64__
|
#endif // __x86_64__
|
||||||
|
|
||||||
|
.macro GET_TEB_HOST reg
|
||||||
|
|
||||||
|
#if defined(__APPLE__) && defined(__x86_64__)
|
||||||
|
// TLS slot 6 reserved for Win64 compatibility
|
||||||
|
// https://github.com/apple/darwin-libpthread/blob/03c4628c8940cca6fd6a82957f683af804f62e7f/private/tsd_private.h#L92-L97
|
||||||
|
mov \reg, gs:[0x30]
|
||||||
|
#elif defined(__linux__) && defined(__x86_64__)
|
||||||
|
mov \reg, fs:[currentThreadTeb@tpoff]
|
||||||
|
#elif defined(__linux__) && defined(__i386__)
|
||||||
|
mov \reg, gs:[currentThreadTeb@ntpoff]
|
||||||
|
#else
|
||||||
|
#error "Unsupported platform"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
.endm
|
||||||
|
|||||||
26
src/main.cpp
26
src/main.cpp
@@ -10,12 +10,6 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "version_info.h"
|
#include "version_info.h"
|
||||||
|
|
||||||
#ifdef __x86_64__
|
|
||||||
#include "setup.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <asm/ldt.h>
|
|
||||||
#include <asm/prctl.h>
|
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@@ -26,9 +20,17 @@
|
|||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <sys/syscall.h>
|
#include <sys/syscall.h>
|
||||||
#include <threads.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <vector>
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
#include "setup.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __linux__
|
||||||
|
#include <asm/ldt.h>
|
||||||
|
#include <asm/prctl.h>
|
||||||
|
#include <threads.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
char **wibo::argv;
|
char **wibo::argv;
|
||||||
int wibo::argc;
|
int wibo::argc;
|
||||||
@@ -49,7 +51,11 @@ void wibo::debug_log(const char *fmt, ...) {
|
|||||||
for (size_t i = 0; i < wibo::debugIndent; i++)
|
for (size_t i = 0; i < wibo::debugIndent; i++)
|
||||||
fprintf(stderr, "\t");
|
fprintf(stderr, "\t");
|
||||||
pthread_t threadId = pthread_self();
|
pthread_t threadId = pthread_self();
|
||||||
|
#ifdef __APPLE__
|
||||||
|
fprintf(stderr, "[thread %p] ", threadId);
|
||||||
|
#else
|
||||||
fprintf(stderr, "[thread %lu] ", threadId);
|
fprintf(stderr, "[thread %lu] ", threadId);
|
||||||
|
#endif
|
||||||
vfprintf(stderr, fmt, args);
|
vfprintf(stderr, fmt, args);
|
||||||
fflush(stderr);
|
fflush(stderr);
|
||||||
}
|
}
|
||||||
@@ -101,8 +107,8 @@ bool wibo::installTibForCurrentThread(TEB *tibPtr) {
|
|||||||
|
|
||||||
currentThreadTeb = tibPtr;
|
currentThreadTeb = tibPtr;
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
tibEntryNumber = x86_64_thread_setup(tibEntryNumber, tibPtr);
|
tibEntryNumber = tebThreadSetup(tibEntryNumber, tibPtr);
|
||||||
if (tibEntryNumber == -1 || tibPtr->CurrentFsSelector == 0) {
|
if (tibEntryNumber < 0 || tibPtr->CurrentFsSelector == 0) {
|
||||||
perror("x86_64_thread_setup failed");
|
perror("x86_64_thread_setup failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -175,9 +175,8 @@ StubFuncType resolveMissingFuncName(const char *dllName, const char *funcName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
StubFuncType resolveMissingFuncOrdinal(const char *dllName, uint16_t ordinal) {
|
StubFuncType resolveMissingFuncOrdinal(const char *dllName, uint16_t ordinal) {
|
||||||
char buf[16];
|
std::string funcName = std::to_string(ordinal);
|
||||||
sprintf(buf, "%d", ordinal);
|
return resolveMissingFuncName(dllName, funcName.c_str());
|
||||||
return resolveMissingFuncName(dllName, buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ModuleRegistry {
|
struct ModuleRegistry {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "entry.h"
|
#include "entry.h"
|
||||||
#include "msvcrt.h"
|
|
||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
|
|||||||
@@ -3,34 +3,47 @@
|
|||||||
#include "kernel32/internal.h"
|
#include "kernel32/internal.h"
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <thread>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
using kernel32::ProcessObject;
|
using kernel32::ProcessObject;
|
||||||
|
|
||||||
namespace wibo {
|
namespace wibo {
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
|
class ProcessManagerImpl {
|
||||||
|
public:
|
||||||
|
virtual ~ProcessManagerImpl() = default;
|
||||||
|
virtual bool init() = 0;
|
||||||
|
virtual void shutdown() = 0;
|
||||||
|
virtual bool addProcess(Pin<ProcessObject> po) = 0;
|
||||||
|
[[nodiscard]] virtual bool running() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SpawnProcessInfo {
|
||||||
|
pid_t pid = -1;
|
||||||
|
int pidfd = -1;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<ProcessManagerImpl> createProcessManagerImpl();
|
||||||
|
int spawnProcess(char *const argv[], char *const envp[], SpawnProcessInfo &info);
|
||||||
|
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
class ProcessManager {
|
class ProcessManager {
|
||||||
public:
|
public:
|
||||||
|
ProcessManager();
|
||||||
~ProcessManager();
|
~ProcessManager();
|
||||||
bool init();
|
bool init();
|
||||||
void shutdown();
|
void shutdown();
|
||||||
bool addProcess(Pin<ProcessObject> po);
|
bool addProcess(Pin<ProcessObject> po);
|
||||||
bool running() const { return mRunning.load(std::memory_order_acquire); }
|
[[nodiscard]] bool running() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void runLoop();
|
std::unique_ptr<detail::ProcessManagerImpl> mImpl;
|
||||||
void wake() const;
|
|
||||||
void checkPidfd(int pidfd);
|
|
||||||
|
|
||||||
mutable std::shared_mutex m;
|
|
||||||
std::atomic<bool> mRunning = false;
|
|
||||||
std::thread mThread;
|
|
||||||
int mEpollFd = -1;
|
|
||||||
int mWakeFd = -1;
|
|
||||||
std::unordered_map<int, Pin<ProcessObject>> mReg;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ProcessManager &processes();
|
ProcessManager &processes();
|
||||||
|
|||||||
@@ -1,223 +1,60 @@
|
|||||||
#include "processes.h"
|
#include "processes.h"
|
||||||
|
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "files.h"
|
#include "files.h"
|
||||||
#include "handles.h"
|
#include "handles.h"
|
||||||
#include "kernel32/internal.h"
|
#include "kernel32/internal.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <linux/sched.h>
|
|
||||||
#include <mutex>
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <shared_mutex>
|
|
||||||
#include <spawn.h>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <strings.h>
|
|
||||||
#include <sys/epoll.h>
|
|
||||||
#include <sys/eventfd.h>
|
|
||||||
#include <sys/prctl.h>
|
|
||||||
#include <sys/syscall.h>
|
|
||||||
#include <sys/wait.h>
|
|
||||||
#include <unistd.h>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace {
|
extern char **environ;
|
||||||
|
|
||||||
inline DWORD decodeExitCode(const siginfo_t &si) {
|
using kernel32::ProcessObject;
|
||||||
switch (si.si_code) {
|
|
||||||
case CLD_EXITED:
|
|
||||||
return static_cast<DWORD>(si.si_status);
|
|
||||||
case CLD_KILLED:
|
|
||||||
case CLD_DUMPED:
|
|
||||||
return 0xC0000000u | static_cast<DWORD>(si.si_status);
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace wibo {
|
namespace wibo {
|
||||||
|
|
||||||
ProcessManager::~ProcessManager() { shutdown(); }
|
ProcessManager::ProcessManager() : mImpl(detail::createProcessManagerImpl()) {}
|
||||||
|
|
||||||
|
ProcessManager::~ProcessManager() = default;
|
||||||
|
|
||||||
bool ProcessManager::init() {
|
bool ProcessManager::init() {
|
||||||
if (mRunning.load(std::memory_order_acquire)) {
|
if (!mImpl) {
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
mEpollFd = epoll_create1(EPOLL_CLOEXEC);
|
|
||||||
if (mEpollFd < 0) {
|
|
||||||
perror("epoll_create1");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return mImpl->init();
|
||||||
mWakeFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
|
||||||
if (mWakeFd < 0) {
|
|
||||||
perror("eventfd");
|
|
||||||
close(mEpollFd);
|
|
||||||
mEpollFd = -1;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
epoll_event ev{};
|
|
||||||
ev.events = EPOLLIN;
|
|
||||||
ev.data.fd = mWakeFd;
|
|
||||||
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeFd, &ev) < 0) {
|
|
||||||
perror("epoll_ctl");
|
|
||||||
close(mWakeFd);
|
|
||||||
mWakeFd = -1;
|
|
||||||
close(mEpollFd);
|
|
||||||
mEpollFd = -1;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
mRunning.store(true, std::memory_order_release);
|
|
||||||
mThread = std::thread(&ProcessManager::runLoop, this);
|
|
||||||
DEBUG_LOG("ProcessManager initialized\n");
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessManager::shutdown() {
|
void ProcessManager::shutdown() {
|
||||||
if (!mRunning.exchange(false, std::memory_order_acq_rel)) {
|
if (mImpl) {
|
||||||
return;
|
mImpl->shutdown();
|
||||||
}
|
|
||||||
wake();
|
|
||||||
if (mThread.joinable()) {
|
|
||||||
mThread.join();
|
|
||||||
}
|
|
||||||
std::lock_guard lk(m);
|
|
||||||
mReg.clear();
|
|
||||||
if (mWakeFd >= 0) {
|
|
||||||
close(mWakeFd);
|
|
||||||
mWakeFd = -1;
|
|
||||||
}
|
|
||||||
if (mEpollFd >= 0) {
|
|
||||||
close(mEpollFd);
|
|
||||||
mEpollFd = -1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ProcessManager::addProcess(Pin<ProcessObject> po) {
|
bool ProcessManager::addProcess(Pin<ProcessObject> po) {
|
||||||
if (!po) {
|
if (!mImpl) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
pid_t pid;
|
return mImpl->addProcess(std::move(po));
|
||||||
int pidfd;
|
|
||||||
{
|
|
||||||
std::lock_guard lk(po->m);
|
|
||||||
pid = po->pid;
|
|
||||||
pidfd = po->pidfd;
|
|
||||||
if (pidfd < 0) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
epoll_event ev{};
|
|
||||||
ev.events = EPOLLIN;
|
|
||||||
ev.data.fd = pidfd;
|
|
||||||
if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, pidfd, &ev) < 0) {
|
|
||||||
perror("epoll_ctl");
|
|
||||||
close(pidfd);
|
|
||||||
po->pidfd = -1;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
{
|
|
||||||
std::lock_guard lk(m);
|
|
||||||
mReg.emplace(pidfd, std::move(po));
|
|
||||||
}
|
|
||||||
DEBUG_LOG("ProcessManager: registered pid %d with pidfd %d\n", pid, pidfd);
|
|
||||||
wake();
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ProcessManager::runLoop() {
|
bool ProcessManager::running() const {
|
||||||
constexpr int kMaxEvents = 64;
|
return mImpl && mImpl->running();
|
||||||
std::array<epoll_event, kMaxEvents> events{};
|
|
||||||
while (mRunning.load(std::memory_order_acquire)) {
|
|
||||||
int n = epoll_wait(mEpollFd, events.data(), kMaxEvents, -1);
|
|
||||||
if (n < 0) {
|
|
||||||
if (errno == EINTR) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
perror("epoll_wait");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
for (int i = 0; i < n; ++i) {
|
|
||||||
const auto &ev = events[i];
|
|
||||||
if (ev.data.fd == mWakeFd) {
|
|
||||||
// Drain eventfd
|
|
||||||
uint64_t n;
|
|
||||||
while (read(mWakeFd, &n, sizeof(n)) == sizeof(n)) {
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
checkPidfd(ev.data.fd);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcessManager::wake() const {
|
|
||||||
if (mWakeFd < 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
uint64_t n = 1;
|
|
||||||
ssize_t r [[maybe_unused]] = write(mWakeFd, &n, sizeof(n));
|
|
||||||
}
|
|
||||||
|
|
||||||
void ProcessManager::checkPidfd(int pidfd) {
|
|
||||||
DEBUG_LOG("ProcessManager: checking pidfd %d\n", pidfd);
|
|
||||||
|
|
||||||
siginfo_t si{};
|
|
||||||
si.si_code = CLD_DUMPED;
|
|
||||||
if (pidfd >= 0) {
|
|
||||||
int rc = waitid(P_PIDFD, pidfd, &si, WEXITED | WNOHANG);
|
|
||||||
if (rc < 0) {
|
|
||||||
// TODO: what to do here?
|
|
||||||
perror("waitid");
|
|
||||||
} else if (rc == 0 && si.si_pid == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
epoll_ctl(mEpollFd, EPOLL_CTL_DEL, pidfd, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_LOG("ProcessManager: pidfd %d exited: code=%d status=%d\n", pidfd, si.si_code, si.si_status);
|
|
||||||
|
|
||||||
Pin<ProcessObject> po;
|
|
||||||
{
|
|
||||||
std::unique_lock lk(m);
|
|
||||||
auto it = mReg.find(pidfd);
|
|
||||||
if (it != mReg.end()) {
|
|
||||||
po = std::move(it->second);
|
|
||||||
mReg.erase(it);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(pidfd);
|
|
||||||
if (!po) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
std::lock_guard lk(po->m);
|
|
||||||
po->signaled = true;
|
|
||||||
po->pidfd = -1;
|
|
||||||
if (!po->forcedExitCode) {
|
|
||||||
po->exitCode = decodeExitCode(si);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
po->cv.notify_all();
|
|
||||||
po->notifyWaiters(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ProcessManager &processes() {
|
ProcessManager &processes() {
|
||||||
static ProcessManager mgr;
|
static ProcessManager mgr;
|
||||||
if (!mgr.init()) {
|
if (!mgr.init()) {
|
||||||
fprintf(stderr, "Failed to initialize ProcessManager\n");
|
std::fprintf(stderr, "Failed to initialize ProcessManager\n");
|
||||||
abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
return mgr;
|
return mgr;
|
||||||
}
|
}
|
||||||
@@ -307,7 +144,7 @@ static std::vector<std::filesystem::path> buildSearchDirectories() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
addFromEnv("WIBO_PATH");
|
addFromEnv("WIBO_PATH");
|
||||||
addFromEnv("WINEPATH"); // Wine compatibility
|
addFromEnv("WINEPATH");
|
||||||
addFromEnv("PATH");
|
addFromEnv("PATH");
|
||||||
return dirs;
|
return dirs;
|
||||||
}
|
}
|
||||||
@@ -371,22 +208,6 @@ std::optional<std::filesystem::path> resolveExecutable(const std::string &comman
|
|||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int spawnClone(pid_t &pid, int &pidfd, char **argv, char **envp) {
|
|
||||||
pid = static_cast<pid_t>(syscall(SYS_clone, CLONE_PIDFD, nullptr, &pidfd));
|
|
||||||
if (pid < 0) {
|
|
||||||
int err = errno;
|
|
||||||
perror("clone");
|
|
||||||
return err;
|
|
||||||
} else if (pid == 0) {
|
|
||||||
prctl(PR_SET_PDEATHSIG, SIGKILL);
|
|
||||||
execve("/proc/self/exe", argv, envp);
|
|
||||||
// If we're still here, something went wrong
|
|
||||||
perror("execve");
|
|
||||||
_exit(127);
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int spawnInternal(const std::vector<std::string> &args, Pin<kernel32::ProcessObject> &pinOut) {
|
static int spawnInternal(const std::vector<std::string> &args, Pin<kernel32::ProcessObject> &pinOut) {
|
||||||
std::vector<char *> argv;
|
std::vector<char *> argv;
|
||||||
argv.reserve(args.size() + 2);
|
argv.reserve(args.size() + 2);
|
||||||
@@ -423,20 +244,19 @@ static int spawnInternal(const std::vector<std::string> &args, Pin<kernel32::Pro
|
|||||||
envp.push_back(const_cast<char *>(s.c_str()));
|
envp.push_back(const_cast<char *>(s.c_str()));
|
||||||
envp.push_back(nullptr);
|
envp.push_back(nullptr);
|
||||||
|
|
||||||
pid_t pid = -1;
|
detail::SpawnProcessInfo info;
|
||||||
int pidfd = -1;
|
int rc = detail::spawnProcess(argv.data(), envp.data(), info);
|
||||||
int rc = spawnClone(pid, pidfd, argv.data(), envp.data());
|
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_LOG("Spawned process with PID %d (pidfd=%d)\n", pid, pidfd);
|
DEBUG_LOG("Spawned process with PID %d (pidfd=%d)\n", info.pid, info.pidfd);
|
||||||
|
|
||||||
auto obj = make_pin<kernel32::ProcessObject>(pid, pidfd);
|
auto obj = make_pin<kernel32::ProcessObject>(info.pid, info.pidfd, true);
|
||||||
pinOut = obj.clone();
|
pinOut = obj.clone();
|
||||||
if (!processes().addProcess(std::move(obj))) {
|
if (!processes().addProcess(std::move(obj))) {
|
||||||
fprintf(stderr, "Failed to add process to process manager\n");
|
std::fprintf(stderr, "Failed to add process to process manager\n");
|
||||||
abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -531,3 +351,4 @@ std::vector<std::string> splitCommandLine(const char *commandLine) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
} // namespace wibo
|
} // namespace wibo
|
||||||
|
|
||||||
278
src/processes_darwin.cpp
Normal file
278
src/processes_darwin.cpp
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
#include "processes.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "handles.h"
|
||||||
|
#include "kernel32/internal.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <atomic>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <csignal>
|
||||||
|
#include <cstring>
|
||||||
|
#include <filesystem>
|
||||||
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
|
#include <shared_mutex>
|
||||||
|
#include <spawn.h>
|
||||||
|
#include <system_error>
|
||||||
|
#include <string>
|
||||||
|
#include <sys/event.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define ENUM_DYLD_BOOL
|
||||||
|
#include <mach-o/dyld.h>
|
||||||
|
|
||||||
|
using kernel32::ProcessObject;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
DWORD decodeExitStatus(int status) {
|
||||||
|
if (WIFEXITED(status)) {
|
||||||
|
return static_cast<DWORD>(WEXITSTATUS(status));
|
||||||
|
}
|
||||||
|
if (WIFSIGNALED(status)) {
|
||||||
|
return 0xC0000000u | static_cast<DWORD>(WTERMSIG(status));
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string &executablePath() {
|
||||||
|
static std::string path;
|
||||||
|
static std::once_flag once;
|
||||||
|
std::call_once(once, [] {
|
||||||
|
uint32_t size = 0;
|
||||||
|
if (_NSGetExecutablePath(nullptr, &size) != 0 && size > 0) {
|
||||||
|
std::string buffer(size, '\0');
|
||||||
|
if (_NSGetExecutablePath(buffer.data(), &size) == 0) {
|
||||||
|
std::error_code ec;
|
||||||
|
auto canonical = std::filesystem::weakly_canonical(buffer.c_str(), ec);
|
||||||
|
if (!ec) {
|
||||||
|
path = canonical.string();
|
||||||
|
} else {
|
||||||
|
path.assign(buffer.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (path.empty()) {
|
||||||
|
path = "wibo";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
class DarwinProcessManager final : public wibo::detail::ProcessManagerImpl {
|
||||||
|
public:
|
||||||
|
bool init() override;
|
||||||
|
void shutdown() override;
|
||||||
|
bool addProcess(Pin<ProcessObject> po) override;
|
||||||
|
[[nodiscard]] bool running() const override { return mRunning.load(std::memory_order_acquire); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void runLoop();
|
||||||
|
void wake() const;
|
||||||
|
void handleExit(pid_t pid);
|
||||||
|
|
||||||
|
mutable std::shared_mutex m;
|
||||||
|
std::atomic<bool> mRunning{false};
|
||||||
|
std::thread mThread;
|
||||||
|
int mKqueueFd = -1;
|
||||||
|
uintptr_t mWakeIdent = 1;
|
||||||
|
std::unordered_map<pid_t, Pin<ProcessObject>> mReg;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace wibo::detail {
|
||||||
|
|
||||||
|
std::unique_ptr<ProcessManagerImpl> createProcessManagerImpl() {
|
||||||
|
return std::make_unique<DarwinProcessManager>();
|
||||||
|
}
|
||||||
|
|
||||||
|
int spawnProcess(char *const argv[], char *const envp[], SpawnProcessInfo &info) {
|
||||||
|
auto &path = executablePath();
|
||||||
|
posix_spawnattr_t attr;
|
||||||
|
int rc = posix_spawnattr_init(&attr);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
sigset_t mask;
|
||||||
|
sigemptyset(&mask);
|
||||||
|
rc = posix_spawnattr_setsigmask(&attr, &mask);
|
||||||
|
if (rc == 0) {
|
||||||
|
rc = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK);
|
||||||
|
}
|
||||||
|
pid_t pid = -1;
|
||||||
|
if (rc == 0) {
|
||||||
|
rc = posix_spawn(&pid, path.c_str(), nullptr, &attr, argv, envp);
|
||||||
|
}
|
||||||
|
posix_spawnattr_destroy(&attr);
|
||||||
|
if (rc != 0) {
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
info.pid = pid;
|
||||||
|
info.pidfd = -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wibo::detail
|
||||||
|
|
||||||
|
bool DarwinProcessManager::init() {
|
||||||
|
if (mRunning.load(std::memory_order_acquire)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mKqueueFd = kqueue();
|
||||||
|
if (mKqueueFd < 0) {
|
||||||
|
perror("kqueue");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct kevent kev;
|
||||||
|
EV_SET(&kev, mWakeIdent, EVFILT_USER, EV_ADD | EV_CLEAR, 0, 0, nullptr);
|
||||||
|
if (kevent(mKqueueFd, &kev, 1, nullptr, 0, nullptr) < 0) {
|
||||||
|
perror("kevent(EV_ADD user)");
|
||||||
|
close(mKqueueFd);
|
||||||
|
mKqueueFd = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mRunning.store(true, std::memory_order_release);
|
||||||
|
mThread = std::thread(&DarwinProcessManager::runLoop, this);
|
||||||
|
DEBUG_LOG("ProcessManager (Darwin) initialized\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DarwinProcessManager::shutdown() {
|
||||||
|
if (!mRunning.exchange(false, std::memory_order_acq_rel)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wake();
|
||||||
|
if (mThread.joinable()) {
|
||||||
|
mThread.join();
|
||||||
|
}
|
||||||
|
std::lock_guard lk(m);
|
||||||
|
mReg.clear();
|
||||||
|
if (mKqueueFd >= 0) {
|
||||||
|
close(mKqueueFd);
|
||||||
|
mKqueueFd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DarwinProcessManager::addProcess(Pin<ProcessObject> po) {
|
||||||
|
if (!po) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pid_t pid;
|
||||||
|
{
|
||||||
|
std::lock_guard lk(po->m);
|
||||||
|
pid = po->pid;
|
||||||
|
}
|
||||||
|
struct kevent kev;
|
||||||
|
EV_SET(&kev, static_cast<uintptr_t>(pid), EVFILT_PROC, EV_ADD | EV_ONESHOT, NOTE_EXIT | NOTE_EXITSTATUS, 0, nullptr);
|
||||||
|
if (kevent(mKqueueFd, &kev, 1, nullptr, 0, nullptr) < 0) {
|
||||||
|
int err = errno;
|
||||||
|
DEBUG_LOG("ProcessManager: kevent add for pid %d failed: %s\n", pid, strerror(err));
|
||||||
|
if (err == ESRCH) {
|
||||||
|
int status = 0;
|
||||||
|
pid_t waited = waitpid(pid, &status, WNOHANG);
|
||||||
|
if (waited <= 0) {
|
||||||
|
waitpid(pid, &status, 0);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard lk(po->m);
|
||||||
|
po->signaled = true;
|
||||||
|
po->pidfd = -1;
|
||||||
|
if (!po->forcedExitCode) {
|
||||||
|
po->exitCode = decodeExitStatus(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
po->cv.notify_all();
|
||||||
|
po->notifyWaiters(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard lk(m);
|
||||||
|
mReg.emplace(pid, std::move(po));
|
||||||
|
}
|
||||||
|
DEBUG_LOG("ProcessManager: registered pid %d\n", pid);
|
||||||
|
wake();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DarwinProcessManager::runLoop() {
|
||||||
|
constexpr int kMaxEvents = 64;
|
||||||
|
std::array<struct kevent, kMaxEvents> events{};
|
||||||
|
while (mRunning.load(std::memory_order_acquire)) {
|
||||||
|
int n = kevent(mKqueueFd, nullptr, 0, events.data(), kMaxEvents, nullptr);
|
||||||
|
if (n < 0) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
perror("kevent");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
const auto &ev = events[i];
|
||||||
|
if (ev.filter == EVFILT_USER) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (ev.filter == EVFILT_PROC && (ev.fflags & NOTE_EXIT)) {
|
||||||
|
handleExit(static_cast<pid_t>(ev.ident));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DarwinProcessManager::wake() const {
|
||||||
|
if (mKqueueFd < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct kevent kev;
|
||||||
|
EV_SET(&kev, mWakeIdent, EVFILT_USER, 0, NOTE_TRIGGER, 0, nullptr);
|
||||||
|
kevent(mKqueueFd, &kev, 1, nullptr, 0, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DarwinProcessManager::handleExit(pid_t pid) {
|
||||||
|
Pin<ProcessObject> po;
|
||||||
|
{
|
||||||
|
std::unique_lock lk(m);
|
||||||
|
auto it = mReg.find(pid);
|
||||||
|
if (it != mReg.end()) {
|
||||||
|
po = std::move(it->second);
|
||||||
|
mReg.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!po) {
|
||||||
|
// Might be a race with registration; still ensure we reap the child.
|
||||||
|
int status = 0;
|
||||||
|
waitpid(pid, &status, WNOHANG);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int status = 0;
|
||||||
|
pid_t waited = waitpid(pid, &status, WNOHANG);
|
||||||
|
if (waited == 0) {
|
||||||
|
// Child still around; block to reap.
|
||||||
|
waited = waitpid(pid, &status, 0);
|
||||||
|
}
|
||||||
|
if (waited < 0) {
|
||||||
|
int err = errno;
|
||||||
|
DEBUG_LOG("ProcessManager: waitpid(%d) failed: %s\n", pid, strerror(err));
|
||||||
|
status = 0;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard lk(po->m);
|
||||||
|
po->signaled = true;
|
||||||
|
po->pidfd = -1;
|
||||||
|
if (!po->forcedExitCode) {
|
||||||
|
po->exitCode = decodeExitStatus(status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
po->cv.notify_all();
|
||||||
|
po->notifyWaiters(false);
|
||||||
|
}
|
||||||
261
src/processes_linux.cpp
Normal file
261
src/processes_linux.cpp
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
#include "processes.h"
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "handles.h"
|
||||||
|
#include "kernel32/internal.h"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <atomic>
|
||||||
|
#include <cerrno>
|
||||||
|
#include <csignal>
|
||||||
|
#include <cstring>
|
||||||
|
#include <memory>
|
||||||
|
#include <shared_mutex>
|
||||||
|
#include <sys/epoll.h>
|
||||||
|
#include <sys/eventfd.h>
|
||||||
|
#include <sys/prctl.h>
|
||||||
|
#include <sys/syscall.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <thread>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <linux/sched.h>
|
||||||
|
|
||||||
|
using kernel32::ProcessObject;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
inline DWORD decodeExitCode(const siginfo_t &si) {
|
||||||
|
switch (si.si_code) {
|
||||||
|
case CLD_EXITED:
|
||||||
|
return static_cast<DWORD>(si.si_status);
|
||||||
|
case CLD_KILLED:
|
||||||
|
case CLD_DUMPED:
|
||||||
|
return 0xC0000000u | static_cast<DWORD>(si.si_status);
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LinuxProcessManager final : public wibo::detail::ProcessManagerImpl {
|
||||||
|
public:
|
||||||
|
bool init() override;
|
||||||
|
void shutdown() override;
|
||||||
|
bool addProcess(Pin<ProcessObject> po) override;
|
||||||
|
[[nodiscard]] bool running() const override { return mRunning.load(std::memory_order_acquire); }
|
||||||
|
|
||||||
|
private:
|
||||||
|
void runLoop();
|
||||||
|
void wake() const;
|
||||||
|
void checkPidfd(int pidfd);
|
||||||
|
|
||||||
|
mutable std::shared_mutex m;
|
||||||
|
std::atomic<bool> mRunning{false};
|
||||||
|
std::thread mThread;
|
||||||
|
int mEpollFd = -1;
|
||||||
|
int mWakeFd = -1;
|
||||||
|
std::unordered_map<int, Pin<ProcessObject>> mReg;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace wibo::detail {
|
||||||
|
|
||||||
|
std::unique_ptr<ProcessManagerImpl> createProcessManagerImpl() {
|
||||||
|
return std::make_unique<LinuxProcessManager>();
|
||||||
|
}
|
||||||
|
|
||||||
|
int spawnProcess(char *const argv[], char *const envp[], SpawnProcessInfo &info) {
|
||||||
|
pid_t pid = static_cast<pid_t>(syscall(SYS_clone, CLONE_PIDFD, nullptr, &info.pidfd));
|
||||||
|
if (pid < 0) {
|
||||||
|
info.pidfd = -1;
|
||||||
|
int err = errno;
|
||||||
|
perror("clone");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
if (pid == 0) {
|
||||||
|
if (prctl(PR_SET_PDEATHSIG, SIGKILL) != 0) {
|
||||||
|
perror("prctl(PR_SET_PDEATHSIG)");
|
||||||
|
}
|
||||||
|
execve("/proc/self/exe", argv, envp);
|
||||||
|
perror("execve");
|
||||||
|
_Exit(127);
|
||||||
|
}
|
||||||
|
info.pid = pid;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wibo::detail
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
bool epollAdd(int epollFd, int fd) {
|
||||||
|
epoll_event ev{};
|
||||||
|
ev.events = EPOLLIN;
|
||||||
|
ev.data.fd = fd;
|
||||||
|
if (epoll_ctl(epollFd, EPOLL_CTL_ADD, fd, &ev) < 0) {
|
||||||
|
perror("epoll_ctl");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool LinuxProcessManager::init() {
|
||||||
|
if (mRunning.load(std::memory_order_acquire)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
mEpollFd = epoll_create1(EPOLL_CLOEXEC);
|
||||||
|
if (mEpollFd < 0) {
|
||||||
|
perror("epoll_create1");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mWakeFd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
|
||||||
|
if (mWakeFd < 0) {
|
||||||
|
perror("eventfd");
|
||||||
|
close(mEpollFd);
|
||||||
|
mEpollFd = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!epollAdd(mEpollFd, mWakeFd)) {
|
||||||
|
close(mWakeFd);
|
||||||
|
mWakeFd = -1;
|
||||||
|
close(mEpollFd);
|
||||||
|
mEpollFd = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mRunning.store(true, std::memory_order_release);
|
||||||
|
mThread = std::thread(&LinuxProcessManager::runLoop, this);
|
||||||
|
DEBUG_LOG("ProcessManager (Linux) initialized\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxProcessManager::shutdown() {
|
||||||
|
if (!mRunning.exchange(false, std::memory_order_acq_rel)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wake();
|
||||||
|
if (mThread.joinable()) {
|
||||||
|
mThread.join();
|
||||||
|
}
|
||||||
|
std::lock_guard lk(m);
|
||||||
|
mReg.clear();
|
||||||
|
if (mWakeFd >= 0) {
|
||||||
|
close(mWakeFd);
|
||||||
|
mWakeFd = -1;
|
||||||
|
}
|
||||||
|
if (mEpollFd >= 0) {
|
||||||
|
close(mEpollFd);
|
||||||
|
mEpollFd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LinuxProcessManager::addProcess(Pin<ProcessObject> po) {
|
||||||
|
if (!po) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pid_t pid;
|
||||||
|
int pidfd;
|
||||||
|
{
|
||||||
|
std::lock_guard lk(po->m);
|
||||||
|
pid = po->pid;
|
||||||
|
pidfd = po->pidfd;
|
||||||
|
if (pidfd < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!epollAdd(mEpollFd, pidfd)) {
|
||||||
|
close(pidfd);
|
||||||
|
po->pidfd = -1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard lk(m);
|
||||||
|
mReg.emplace(pidfd, std::move(po));
|
||||||
|
}
|
||||||
|
DEBUG_LOG("ProcessManager: registered pid %d with pidfd %d\n", pid, pidfd);
|
||||||
|
wake();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxProcessManager::runLoop() {
|
||||||
|
constexpr int kMaxEvents = 64;
|
||||||
|
std::array<epoll_event, kMaxEvents> events{};
|
||||||
|
while (mRunning.load(std::memory_order_acquire)) {
|
||||||
|
int n = epoll_wait(mEpollFd, events.data(), kMaxEvents, -1);
|
||||||
|
if (n < 0) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
perror("epoll_wait");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < n; ++i) {
|
||||||
|
const auto &ev = events[i];
|
||||||
|
if (ev.data.fd == mWakeFd) {
|
||||||
|
uint64_t value;
|
||||||
|
while (read(mWakeFd, &value, sizeof(value)) == sizeof(value)) {
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
checkPidfd(ev.data.fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxProcessManager::wake() const {
|
||||||
|
if (mWakeFd < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uint64_t n = 1;
|
||||||
|
ssize_t r [[maybe_unused]] = write(mWakeFd, &n, sizeof(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LinuxProcessManager::checkPidfd(int pidfd) {
|
||||||
|
DEBUG_LOG("ProcessManager: checking pidfd %d\n", pidfd);
|
||||||
|
|
||||||
|
siginfo_t si{};
|
||||||
|
si.si_code = CLD_DUMPED;
|
||||||
|
if (pidfd >= 0) {
|
||||||
|
int rc = waitid(P_PIDFD, pidfd, &si, WEXITED | WNOHANG);
|
||||||
|
if (rc < 0) {
|
||||||
|
perror("waitid");
|
||||||
|
} else if (rc == 0 && si.si_pid == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
epoll_ctl(mEpollFd, EPOLL_CTL_DEL, pidfd, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
DEBUG_LOG("ProcessManager: pidfd %d exited: code=%d status=%d\n", pidfd, si.si_code, si.si_status);
|
||||||
|
|
||||||
|
Pin<ProcessObject> po;
|
||||||
|
{
|
||||||
|
std::unique_lock lk(m);
|
||||||
|
auto it = mReg.find(pidfd);
|
||||||
|
if (it != mReg.end()) {
|
||||||
|
po = std::move(it->second);
|
||||||
|
mReg.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(pidfd);
|
||||||
|
if (!po) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
std::lock_guard lk(po->m);
|
||||||
|
po->signaled = true;
|
||||||
|
po->pidfd = -1;
|
||||||
|
if (!po->forcedExitCode) {
|
||||||
|
po->exitCode = decodeExitCode(si);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
po->cv.notify_all();
|
||||||
|
po->notifyWaiters(false);
|
||||||
|
}
|
||||||
|
|
||||||
295
src/setup.S
295
src/setup.S
@@ -1,18 +1,25 @@
|
|||||||
#include "macros.S"
|
#include "macros.S"
|
||||||
|
#ifndef __APPLE__
|
||||||
.section .note.GNU-stack, "", @progbits
|
.section .note.GNU-stack, "", @progbits
|
||||||
|
#endif
|
||||||
.text
|
.text
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __APPLE__
|
||||||
|
.zerofill RESV32,RESV32,_wibo_reserve,0x7E000000-0x1000
|
||||||
|
.no_dead_strip _wibo_reserve
|
||||||
|
#endif
|
||||||
|
|
||||||
# int x86_64_thread_setup(int entry_number, void *teb)
|
#if defined(__x86_64__) && !defined(__APPLE__)
|
||||||
.globl x86_64_thread_setup
|
|
||||||
.type x86_64_thread_setup, @function
|
# int tebThreadSetup(int entryNumber, TEB *teb)
|
||||||
x86_64_thread_setup:
|
.globl tebThreadSetup
|
||||||
|
.type tebThreadSetup, @function
|
||||||
|
tebThreadSetup:
|
||||||
push rbx # save rbx
|
push rbx # save rbx
|
||||||
mov r8, rsp # save host stack
|
mov r8, rsp # save host stack
|
||||||
rdfsbase r9 # read host FS base
|
rdfsbase r9 # read host FS base
|
||||||
mov rdx, qword ptr [rsi+TEB_SP] # fetch guest stack
|
mov rdx, qword ptr [rsi+TEB_SP] # fetch guest stack
|
||||||
LJMP32 # far jump into 32-bit code
|
LJMP32 rsi # far jump into 32-bit code
|
||||||
mov ax, 0x2b # user data segment (Linux)
|
mov ax, 0x2b # user data segment (Linux)
|
||||||
mov ds, ax # setup data segment
|
mov ds, ax # setup data segment
|
||||||
mov es, ax # setup extra segment
|
mov es, ax # setup extra segment
|
||||||
@@ -38,21 +45,23 @@ x86_64_thread_setup:
|
|||||||
mov eax, -1 # return -1
|
mov eax, -1 # return -1
|
||||||
2:
|
2:
|
||||||
add esp, 0x10 # cleanup stack
|
add esp, 0x10 # cleanup stack
|
||||||
LJMP64 # far jump into 64-bit code
|
LJMP64 esi # far jump into 64-bit code
|
||||||
cdqe # sign-extend eax to rax
|
cdqe # sign-extend eax to rax
|
||||||
mov rsp, r8 # switch to host stack
|
mov rsp, r8 # switch to host stack
|
||||||
wrfsbase r9 # restore host FS base
|
wrfsbase r9 # restore host FS base
|
||||||
pop rbx # restore rbx
|
pop rbx # restore rbx
|
||||||
ret
|
ret
|
||||||
.size x86_64_thread_setup, .-x86_64_thread_setup
|
.size tebThreadSetup, .-tebThreadSetup
|
||||||
|
|
||||||
#endif // __x86_64__
|
#endif // __x86_64__
|
||||||
|
|
||||||
.altmacro
|
|
||||||
.code32
|
.code32
|
||||||
|
|
||||||
.macro stubThunkX number
|
.macro stubThunkX number
|
||||||
#ifdef __x86_64__
|
#if defined(__APPLE__)
|
||||||
|
.globl __Z9stubThunkILm\()\number\()EEvv
|
||||||
|
__Z9stubThunkILm\()\number\()EEvv:
|
||||||
|
#elif defined(__x86_64__)
|
||||||
.globl _Z9stubThunkILm\()\number\()EEvv
|
.globl _Z9stubThunkILm\()\number\()EEvv
|
||||||
.type _Z9stubThunkILm\()\number\()EEvv, @function
|
.type _Z9stubThunkILm\()\number\()EEvv, @function
|
||||||
_Z9stubThunkILm\()\number\()EEvv:
|
_Z9stubThunkILm\()\number\()EEvv:
|
||||||
@@ -64,11 +73,267 @@ _Z9stubThunkILj\()\number\()EEvv:
|
|||||||
pop eax
|
pop eax
|
||||||
push \number
|
push \number
|
||||||
push eax
|
push eax
|
||||||
|
#ifdef __APPLE__
|
||||||
|
jmp _thunk_entry_stubBase
|
||||||
|
#else
|
||||||
jmp thunk_entry_stubBase
|
jmp thunk_entry_stubBase
|
||||||
|
#endif
|
||||||
.endm
|
.endm
|
||||||
|
|
||||||
.set i, 0
|
stubThunkX 0
|
||||||
.rept 256
|
stubThunkX 1
|
||||||
stubThunkX %i
|
stubThunkX 2
|
||||||
.set i, i+1
|
stubThunkX 3
|
||||||
.endr
|
stubThunkX 4
|
||||||
|
stubThunkX 5
|
||||||
|
stubThunkX 6
|
||||||
|
stubThunkX 7
|
||||||
|
stubThunkX 8
|
||||||
|
stubThunkX 9
|
||||||
|
stubThunkX 10
|
||||||
|
stubThunkX 11
|
||||||
|
stubThunkX 12
|
||||||
|
stubThunkX 13
|
||||||
|
stubThunkX 14
|
||||||
|
stubThunkX 15
|
||||||
|
stubThunkX 16
|
||||||
|
stubThunkX 17
|
||||||
|
stubThunkX 18
|
||||||
|
stubThunkX 19
|
||||||
|
stubThunkX 20
|
||||||
|
stubThunkX 21
|
||||||
|
stubThunkX 22
|
||||||
|
stubThunkX 23
|
||||||
|
stubThunkX 24
|
||||||
|
stubThunkX 25
|
||||||
|
stubThunkX 26
|
||||||
|
stubThunkX 27
|
||||||
|
stubThunkX 28
|
||||||
|
stubThunkX 29
|
||||||
|
stubThunkX 30
|
||||||
|
stubThunkX 31
|
||||||
|
stubThunkX 32
|
||||||
|
stubThunkX 33
|
||||||
|
stubThunkX 34
|
||||||
|
stubThunkX 35
|
||||||
|
stubThunkX 36
|
||||||
|
stubThunkX 37
|
||||||
|
stubThunkX 38
|
||||||
|
stubThunkX 39
|
||||||
|
stubThunkX 40
|
||||||
|
stubThunkX 41
|
||||||
|
stubThunkX 42
|
||||||
|
stubThunkX 43
|
||||||
|
stubThunkX 44
|
||||||
|
stubThunkX 45
|
||||||
|
stubThunkX 46
|
||||||
|
stubThunkX 47
|
||||||
|
stubThunkX 48
|
||||||
|
stubThunkX 49
|
||||||
|
stubThunkX 50
|
||||||
|
stubThunkX 51
|
||||||
|
stubThunkX 52
|
||||||
|
stubThunkX 53
|
||||||
|
stubThunkX 54
|
||||||
|
stubThunkX 55
|
||||||
|
stubThunkX 56
|
||||||
|
stubThunkX 57
|
||||||
|
stubThunkX 58
|
||||||
|
stubThunkX 59
|
||||||
|
stubThunkX 60
|
||||||
|
stubThunkX 61
|
||||||
|
stubThunkX 62
|
||||||
|
stubThunkX 63
|
||||||
|
stubThunkX 64
|
||||||
|
stubThunkX 65
|
||||||
|
stubThunkX 66
|
||||||
|
stubThunkX 67
|
||||||
|
stubThunkX 68
|
||||||
|
stubThunkX 69
|
||||||
|
stubThunkX 70
|
||||||
|
stubThunkX 71
|
||||||
|
stubThunkX 72
|
||||||
|
stubThunkX 73
|
||||||
|
stubThunkX 74
|
||||||
|
stubThunkX 75
|
||||||
|
stubThunkX 76
|
||||||
|
stubThunkX 77
|
||||||
|
stubThunkX 78
|
||||||
|
stubThunkX 79
|
||||||
|
stubThunkX 80
|
||||||
|
stubThunkX 81
|
||||||
|
stubThunkX 82
|
||||||
|
stubThunkX 83
|
||||||
|
stubThunkX 84
|
||||||
|
stubThunkX 85
|
||||||
|
stubThunkX 86
|
||||||
|
stubThunkX 87
|
||||||
|
stubThunkX 88
|
||||||
|
stubThunkX 89
|
||||||
|
stubThunkX 90
|
||||||
|
stubThunkX 91
|
||||||
|
stubThunkX 92
|
||||||
|
stubThunkX 93
|
||||||
|
stubThunkX 94
|
||||||
|
stubThunkX 95
|
||||||
|
stubThunkX 96
|
||||||
|
stubThunkX 97
|
||||||
|
stubThunkX 98
|
||||||
|
stubThunkX 99
|
||||||
|
stubThunkX 100
|
||||||
|
stubThunkX 101
|
||||||
|
stubThunkX 102
|
||||||
|
stubThunkX 103
|
||||||
|
stubThunkX 104
|
||||||
|
stubThunkX 105
|
||||||
|
stubThunkX 106
|
||||||
|
stubThunkX 107
|
||||||
|
stubThunkX 108
|
||||||
|
stubThunkX 109
|
||||||
|
stubThunkX 110
|
||||||
|
stubThunkX 111
|
||||||
|
stubThunkX 112
|
||||||
|
stubThunkX 113
|
||||||
|
stubThunkX 114
|
||||||
|
stubThunkX 115
|
||||||
|
stubThunkX 116
|
||||||
|
stubThunkX 117
|
||||||
|
stubThunkX 118
|
||||||
|
stubThunkX 119
|
||||||
|
stubThunkX 120
|
||||||
|
stubThunkX 121
|
||||||
|
stubThunkX 122
|
||||||
|
stubThunkX 123
|
||||||
|
stubThunkX 124
|
||||||
|
stubThunkX 125
|
||||||
|
stubThunkX 126
|
||||||
|
stubThunkX 127
|
||||||
|
stubThunkX 128
|
||||||
|
stubThunkX 129
|
||||||
|
stubThunkX 130
|
||||||
|
stubThunkX 131
|
||||||
|
stubThunkX 132
|
||||||
|
stubThunkX 133
|
||||||
|
stubThunkX 134
|
||||||
|
stubThunkX 135
|
||||||
|
stubThunkX 136
|
||||||
|
stubThunkX 137
|
||||||
|
stubThunkX 138
|
||||||
|
stubThunkX 139
|
||||||
|
stubThunkX 140
|
||||||
|
stubThunkX 141
|
||||||
|
stubThunkX 142
|
||||||
|
stubThunkX 143
|
||||||
|
stubThunkX 144
|
||||||
|
stubThunkX 145
|
||||||
|
stubThunkX 146
|
||||||
|
stubThunkX 147
|
||||||
|
stubThunkX 148
|
||||||
|
stubThunkX 149
|
||||||
|
stubThunkX 150
|
||||||
|
stubThunkX 151
|
||||||
|
stubThunkX 152
|
||||||
|
stubThunkX 153
|
||||||
|
stubThunkX 154
|
||||||
|
stubThunkX 155
|
||||||
|
stubThunkX 156
|
||||||
|
stubThunkX 157
|
||||||
|
stubThunkX 158
|
||||||
|
stubThunkX 159
|
||||||
|
stubThunkX 160
|
||||||
|
stubThunkX 161
|
||||||
|
stubThunkX 162
|
||||||
|
stubThunkX 163
|
||||||
|
stubThunkX 164
|
||||||
|
stubThunkX 165
|
||||||
|
stubThunkX 166
|
||||||
|
stubThunkX 167
|
||||||
|
stubThunkX 168
|
||||||
|
stubThunkX 169
|
||||||
|
stubThunkX 170
|
||||||
|
stubThunkX 171
|
||||||
|
stubThunkX 172
|
||||||
|
stubThunkX 173
|
||||||
|
stubThunkX 174
|
||||||
|
stubThunkX 175
|
||||||
|
stubThunkX 176
|
||||||
|
stubThunkX 177
|
||||||
|
stubThunkX 178
|
||||||
|
stubThunkX 179
|
||||||
|
stubThunkX 180
|
||||||
|
stubThunkX 181
|
||||||
|
stubThunkX 182
|
||||||
|
stubThunkX 183
|
||||||
|
stubThunkX 184
|
||||||
|
stubThunkX 185
|
||||||
|
stubThunkX 186
|
||||||
|
stubThunkX 187
|
||||||
|
stubThunkX 188
|
||||||
|
stubThunkX 189
|
||||||
|
stubThunkX 190
|
||||||
|
stubThunkX 191
|
||||||
|
stubThunkX 192
|
||||||
|
stubThunkX 193
|
||||||
|
stubThunkX 194
|
||||||
|
stubThunkX 195
|
||||||
|
stubThunkX 196
|
||||||
|
stubThunkX 197
|
||||||
|
stubThunkX 198
|
||||||
|
stubThunkX 199
|
||||||
|
stubThunkX 200
|
||||||
|
stubThunkX 201
|
||||||
|
stubThunkX 202
|
||||||
|
stubThunkX 203
|
||||||
|
stubThunkX 204
|
||||||
|
stubThunkX 205
|
||||||
|
stubThunkX 206
|
||||||
|
stubThunkX 207
|
||||||
|
stubThunkX 208
|
||||||
|
stubThunkX 209
|
||||||
|
stubThunkX 210
|
||||||
|
stubThunkX 211
|
||||||
|
stubThunkX 212
|
||||||
|
stubThunkX 213
|
||||||
|
stubThunkX 214
|
||||||
|
stubThunkX 215
|
||||||
|
stubThunkX 216
|
||||||
|
stubThunkX 217
|
||||||
|
stubThunkX 218
|
||||||
|
stubThunkX 219
|
||||||
|
stubThunkX 220
|
||||||
|
stubThunkX 221
|
||||||
|
stubThunkX 222
|
||||||
|
stubThunkX 223
|
||||||
|
stubThunkX 224
|
||||||
|
stubThunkX 225
|
||||||
|
stubThunkX 226
|
||||||
|
stubThunkX 227
|
||||||
|
stubThunkX 228
|
||||||
|
stubThunkX 229
|
||||||
|
stubThunkX 230
|
||||||
|
stubThunkX 231
|
||||||
|
stubThunkX 232
|
||||||
|
stubThunkX 233
|
||||||
|
stubThunkX 234
|
||||||
|
stubThunkX 235
|
||||||
|
stubThunkX 236
|
||||||
|
stubThunkX 237
|
||||||
|
stubThunkX 238
|
||||||
|
stubThunkX 239
|
||||||
|
stubThunkX 240
|
||||||
|
stubThunkX 241
|
||||||
|
stubThunkX 242
|
||||||
|
stubThunkX 243
|
||||||
|
stubThunkX 244
|
||||||
|
stubThunkX 245
|
||||||
|
stubThunkX 246
|
||||||
|
stubThunkX 247
|
||||||
|
stubThunkX 248
|
||||||
|
stubThunkX 249
|
||||||
|
stubThunkX 250
|
||||||
|
stubThunkX 251
|
||||||
|
stubThunkX 252
|
||||||
|
stubThunkX 253
|
||||||
|
stubThunkX 254
|
||||||
|
stubThunkX 255
|
||||||
|
stubThunkX 256
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
int x86_64_thread_setup(int entry_number, void *teb);
|
int tebThreadSetup(int entryNumber, TEB *teb);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
|||||||
105
src/setup_darwin.cpp
Normal file
105
src/setup_darwin.cpp
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
#include "common.h"
|
||||||
|
#include "setup.h"
|
||||||
|
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
|
#include <cerrno>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include <architecture/i386/table.h>
|
||||||
|
#include <i386/user_ldt.h>
|
||||||
|
|
||||||
|
// https://github.com/apple/darwin-libpthread/blob/03c4628c8940cca6fd6a82957f683af804f62e7f/private/tsd_private.h#L92-L97
|
||||||
|
#define _PTHREAD_TSD_SLOT_RESERVED_WIN64 6
|
||||||
|
|
||||||
|
#define USER_PRIVILEGE 3
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
inline ldt_entry createLdtEntry(uint32_t base, uint32_t size, bool code) {
|
||||||
|
uint32_t limit;
|
||||||
|
uint8_t granular;
|
||||||
|
if (size > 0xFFFFF) {
|
||||||
|
limit = (size - 1) >> 12;
|
||||||
|
granular = DESC_GRAN_PAGE;
|
||||||
|
} else {
|
||||||
|
limit = size - 1;
|
||||||
|
granular = DESC_GRAN_BYTE;
|
||||||
|
}
|
||||||
|
ldt_entry entry; // NOLINT(cppcoreguidelines-pro-type-member-init)
|
||||||
|
// Must memset to zero to avoid uninitialized padding bytes
|
||||||
|
std::memset(&entry, 0, sizeof(ldt_entry));
|
||||||
|
entry.code.limit00 = static_cast<uint16_t>(limit);
|
||||||
|
entry.code.base00 = static_cast<uint16_t>(base);
|
||||||
|
entry.code.base16 = static_cast<uint8_t>(base >> 16);
|
||||||
|
entry.code.type = code ? DESC_CODE_READ : DESC_DATA_WRITE;
|
||||||
|
entry.code.dpl = USER_PRIVILEGE;
|
||||||
|
entry.code.present = 1;
|
||||||
|
entry.code.limit16 = static_cast<uint8_t>(limit >> 16);
|
||||||
|
entry.code.opsz = DESC_CODE_32B;
|
||||||
|
entry.code.granular = granular;
|
||||||
|
entry.code.base24 = static_cast<uint8_t>(base >> 24);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr int createSelector(int entryNumber) { return (entryNumber << 3) | 0x4 /* TI=1 */ | USER_PRIVILEGE; }
|
||||||
|
|
||||||
|
inline void writeTsdSlot(uint32_t slot, uint64_t val) {
|
||||||
|
// mov qword ptr gs:[slot*8], val
|
||||||
|
*(volatile uint64_t __seg_gs *)(slot * sizeof(void *)) = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int tebThreadSetup(int entryNumber, TEB *teb) {
|
||||||
|
bool alloc = entryNumber == -1;
|
||||||
|
if (alloc) {
|
||||||
|
ldt_entry unused{};
|
||||||
|
entryNumber = i386_get_ldt(0, &unused, 1);
|
||||||
|
if (entryNumber < 0) {
|
||||||
|
return entryNumber;
|
||||||
|
}
|
||||||
|
DEBUG_LOG("Allocating LDT entry %d\n", entryNumber);
|
||||||
|
// Create code LDT entry at entry_number + 1
|
||||||
|
ldt_entry codeLdt = createLdtEntry(0, 0xFFFFFFFF, true);
|
||||||
|
int codeLdtEntry = entryNumber++;
|
||||||
|
int ret = i386_set_ldt(codeLdtEntry, &codeLdt, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
} else if (ret != codeLdtEntry) {
|
||||||
|
errno = EALREADY;
|
||||||
|
return -EALREADY;
|
||||||
|
}
|
||||||
|
DEBUG_LOG("Code selector %x\n", createSelector(ret));
|
||||||
|
// Create data LDT entry at entry_number + 2
|
||||||
|
ldt_entry dataLdt = createLdtEntry(0, 0xFFFFFFFF, false);
|
||||||
|
int dataLdtEntry = entryNumber++;
|
||||||
|
ret = i386_set_ldt(dataLdtEntry, &dataLdt, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
} else if (ret != dataLdtEntry) {
|
||||||
|
errno = EALREADY;
|
||||||
|
return -EALREADY;
|
||||||
|
}
|
||||||
|
DEBUG_LOG("Data selector %x\n", createSelector(dataLdtEntry));
|
||||||
|
}
|
||||||
|
uintptr_t tebBase = reinterpret_cast<uintptr_t>(teb);
|
||||||
|
if (tebBase > 0xFFFFFFFF) {
|
||||||
|
DEBUG_LOG("TEB base address exceeds 32-bit limit\n");
|
||||||
|
errno = EINVAL;
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
// Store the TEB base address in the reserved slot for Windows 64-bit (gs:[0x30])
|
||||||
|
writeTsdSlot(_PTHREAD_TSD_SLOT_RESERVED_WIN64, static_cast<uint32_t>(tebBase));
|
||||||
|
// Rosetta 2 requires size 0x1000 (limit 0xFFF) specifically
|
||||||
|
ldt_entry fsLdt = createLdtEntry(static_cast<uint32_t>(tebBase), 0x1000, false);
|
||||||
|
int ret = i386_set_ldt(entryNumber, &fsLdt, 1);
|
||||||
|
if (ret < 0) {
|
||||||
|
return ret;
|
||||||
|
} else if (ret != entryNumber) {
|
||||||
|
errno = EALREADY;
|
||||||
|
return -EALREADY;
|
||||||
|
}
|
||||||
|
teb->CurrentFsSelector = createSelector(entryNumber);
|
||||||
|
return entryNumber;
|
||||||
|
}
|
||||||
@@ -538,7 +538,8 @@ typedef struct _TEB {
|
|||||||
WORD CurrentGsSelector;
|
WORD CurrentGsSelector;
|
||||||
void *CurrentStackPointer;
|
void *CurrentStackPointer;
|
||||||
#ifdef __x86_64__
|
#ifdef __x86_64__
|
||||||
void *CurrentFsBase;
|
void *HostFsBase;
|
||||||
|
void *HostGsBase;
|
||||||
#endif
|
#endif
|
||||||
} TEB;
|
} TEB;
|
||||||
typedef GUEST_PTR PTEB;
|
typedef GUEST_PTR PTEB;
|
||||||
|
|||||||
@@ -49,6 +49,8 @@ if "LIBCLANG_PATH" in os.environ:
|
|||||||
f"Warning: LIBCLANG_PATH={libclang_path} is not a file or directory\n"
|
f"Warning: LIBCLANG_PATH={libclang_path} is not a file or directory\n"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
SYMBOL_PREFIX = "_" if sys.platform == "darwin" else ""
|
||||||
|
|
||||||
|
|
||||||
class Arch(str, Enum):
|
class Arch(str, Enum):
|
||||||
X86 = "x86"
|
X86 = "x86"
|
||||||
@@ -524,7 +526,7 @@ def emit_cc_thunk32(f: FuncInfo | TypedefInfo, lines: List[str]):
|
|||||||
|
|
||||||
# Get current TEB
|
# Get current TEB
|
||||||
if host_to_guest:
|
if host_to_guest:
|
||||||
lines.append("\tmov ecx, gs:[currentThreadTeb@ntpoff]")
|
lines.append("\tGET_TEB_HOST ecx")
|
||||||
else:
|
else:
|
||||||
lines.append("\tmov ecx, fs:[TEB_SELF]")
|
lines.append("\tmov ecx, fs:[TEB_SELF]")
|
||||||
|
|
||||||
@@ -613,7 +615,7 @@ def emit_cc_thunk32(f: FuncInfo | TypedefInfo, lines: List[str]):
|
|||||||
if host_to_guest:
|
if host_to_guest:
|
||||||
lines.append("\tmov ecx, fs:[TEB_SELF]")
|
lines.append("\tmov ecx, fs:[TEB_SELF]")
|
||||||
else:
|
else:
|
||||||
lines.append("\tmov ecx, gs:[currentThreadTeb@ntpoff]")
|
lines.append("\tGET_TEB_HOST ecx")
|
||||||
lines.append("\tmov ax, fs")
|
lines.append("\tmov ax, fs")
|
||||||
lines.append("\tmov dx, word ptr [ecx+TEB_FS_SEL]")
|
lines.append("\tmov dx, word ptr [ecx+TEB_FS_SEL]")
|
||||||
lines.append("\tmov word ptr [ecx+TEB_FS_SEL], ax")
|
lines.append("\tmov word ptr [ecx+TEB_FS_SEL], ax")
|
||||||
@@ -699,7 +701,7 @@ def emit_cc_thunk64(f: FuncInfo | TypedefInfo, lines: List[str]):
|
|||||||
f.args,
|
f.args,
|
||||||
f.source_cc,
|
f.source_cc,
|
||||||
Arch.X86_64 if host_to_guest else Arch.X86,
|
Arch.X86_64 if host_to_guest else Arch.X86,
|
||||||
stack_offset=24 if host_to_guest else 16,
|
stack_offset=24 if host_to_guest else 20,
|
||||||
skip_args=1 if host_to_guest else 0,
|
skip_args=1 if host_to_guest else 0,
|
||||||
)
|
)
|
||||||
target_layout = compute_arg_layout(
|
target_layout = compute_arg_layout(
|
||||||
@@ -710,22 +712,23 @@ def emit_cc_thunk64(f: FuncInfo | TypedefInfo, lines: List[str]):
|
|||||||
lines.append(".code64")
|
lines.append(".code64")
|
||||||
|
|
||||||
# Save rbx and rbp
|
# Save rbx and rbp
|
||||||
lines.append("\tpush rbx")
|
|
||||||
lines.append("\tpush rbp")
|
lines.append("\tpush rbp")
|
||||||
|
lines.append("\tpush rbx")
|
||||||
|
|
||||||
# Stash host stack in r10
|
# Stash host stack in r10
|
||||||
lines.append("\tmov r10, rsp")
|
lines.append("\tmov r10, rsp")
|
||||||
|
|
||||||
# Get current TEB
|
# Get current TEB
|
||||||
lines.append("\tmov rcx, fs:[currentThreadTeb@tpoff]")
|
lines.append("\tGET_TEB_HOST rbx")
|
||||||
|
|
||||||
# Save FS base
|
if sys.platform != "darwin":
|
||||||
lines.append("\trdfsbase r9")
|
# Save FS base
|
||||||
lines.append("\tmov qword ptr [rcx+TEB_FSBASE], r9")
|
lines.append("\trdfsbase r9")
|
||||||
|
lines.append("\tmov qword ptr [rbx+TEB_FSBASE], r9")
|
||||||
|
|
||||||
# Save RSP and load guest stack
|
# Save RSP and load guest stack
|
||||||
lines.append("\tmov rbp, qword ptr [rcx+TEB_SP]")
|
lines.append("\tmov rbp, qword ptr [rbx+TEB_SP]")
|
||||||
lines.append("\tmov qword ptr [rcx+TEB_SP], rsp")
|
lines.append("\tmov qword ptr [rbx+TEB_SP], rsp")
|
||||||
lines.append("\tmov rsp, rbp")
|
lines.append("\tmov rsp, rbp")
|
||||||
|
|
||||||
# Allocate stack space for arguments
|
# Allocate stack space for arguments
|
||||||
@@ -758,36 +761,37 @@ def emit_cc_thunk64(f: FuncInfo | TypedefInfo, lines: List[str]):
|
|||||||
lines.append(f"\tmov {ptr_type} [rsp+{target.stack_offset}], {register}")
|
lines.append(f"\tmov {ptr_type} [rsp+{target.stack_offset}], {register}")
|
||||||
|
|
||||||
# Jump to 32-bit mode
|
# Jump to 32-bit mode
|
||||||
lines.append("\tLJMP32")
|
lines.append("\tLJMP32 rbx")
|
||||||
|
|
||||||
# Setup FS selector
|
# Setup FS selector
|
||||||
lines.append("\tmov ax, word ptr [ecx+TEB_FS_SEL]")
|
lines.append("\tmov ax, word ptr [ebx+TEB_FS_SEL]")
|
||||||
lines.append("\tmov fs, ax")
|
lines.append("\tmov fs, ax")
|
||||||
|
|
||||||
# Call into target
|
# Call into target
|
||||||
lines.append(f"\tcall {call_target}")
|
lines.append(f"\tcall {call_target}")
|
||||||
|
|
||||||
# Get current TEB
|
# Get current TEB (32-bit code may clobber ebx)
|
||||||
lines.append("\tmov ecx, fs:[TEB_SELF]")
|
lines.append("\tmov ebx, fs:[TEB_SELF]")
|
||||||
|
|
||||||
# Jump back to 64-bit
|
# Jump back to 64-bit
|
||||||
lines.append("\tLJMP64")
|
lines.append("\tLJMP64 ebx")
|
||||||
|
|
||||||
# Sign extend return value if necessary
|
# Sign extend return value if necessary
|
||||||
if f.return_type.sign_extended:
|
if f.return_type.sign_extended:
|
||||||
lines.append("\tcdqe")
|
lines.append("\tcdqe")
|
||||||
|
|
||||||
# Restore FS base
|
if sys.platform != "darwin":
|
||||||
lines.append("\tmov r9, qword ptr [rcx+TEB_FSBASE]")
|
# Restore FS base
|
||||||
lines.append("\twrfsbase r9")
|
lines.append("\tmov r9, qword ptr [rbx+TEB_FSBASE]")
|
||||||
|
lines.append("\twrfsbase r9")
|
||||||
|
|
||||||
# Restore host stack
|
# Restore host stack
|
||||||
lines.append("\tmov rsp, qword ptr [rcx+TEB_SP]")
|
lines.append("\tmov rsp, qword ptr [rbx+TEB_SP]")
|
||||||
lines.append("\tmov qword ptr [rcx+TEB_SP], rbp")
|
lines.append("\tmov qword ptr [rbx+TEB_SP], rbp")
|
||||||
|
|
||||||
# Restore rbp, rbx and return
|
# Restore rbp, rbx and return
|
||||||
lines.append("\tpop rbp")
|
|
||||||
lines.append("\tpop rbx")
|
lines.append("\tpop rbx")
|
||||||
|
lines.append("\tpop rbp")
|
||||||
lines.append("\tret")
|
lines.append("\tret")
|
||||||
else:
|
else:
|
||||||
lines.append(".code32")
|
lines.append(".code32")
|
||||||
@@ -796,27 +800,30 @@ def emit_cc_thunk64(f: FuncInfo | TypedefInfo, lines: List[str]):
|
|||||||
lines.append("\tpush ebp")
|
lines.append("\tpush ebp")
|
||||||
lines.append("\tpush esi")
|
lines.append("\tpush esi")
|
||||||
lines.append("\tpush edi")
|
lines.append("\tpush edi")
|
||||||
|
lines.append("\tpush ebx")
|
||||||
|
|
||||||
# Get current TEB
|
# Get current TEB
|
||||||
lines.append("\tmov ecx, fs:[TEB_SELF]")
|
lines.append("\tmov ebx, fs:[TEB_SELF]")
|
||||||
|
|
||||||
# Save fs segment
|
if sys.platform != "darwin":
|
||||||
lines.append("\tmov di, fs")
|
# Save fs segment
|
||||||
lines.append("\tmov word ptr [ecx+TEB_FS_SEL], di")
|
lines.append("\tmov di, fs")
|
||||||
|
lines.append("\tmov word ptr [ebx+TEB_FS_SEL], di")
|
||||||
|
|
||||||
# Jump back to 64-bit
|
# Jump back to 64-bit
|
||||||
lines.append("\tLJMP64")
|
lines.append("\tLJMP64 ebx")
|
||||||
|
|
||||||
# Restore FS base
|
if sys.platform != "darwin":
|
||||||
lines.append("\tmov r9, qword ptr [rcx+TEB_FSBASE]")
|
# Restore FS base
|
||||||
lines.append("\twrfsbase r9")
|
lines.append("\tmov r9, qword ptr [rbx+TEB_FSBASE]")
|
||||||
|
lines.append("\twrfsbase r9")
|
||||||
|
|
||||||
# Stash guest stack in r10
|
# Stash guest stack in r10
|
||||||
lines.append("\tmov r10, rsp")
|
lines.append("\tmov r10, rsp")
|
||||||
|
|
||||||
# Restore host stack
|
# Restore host stack
|
||||||
lines.append("\tmov rbp, qword ptr [rcx+TEB_SP]")
|
lines.append("\tmov rbp, qword ptr [rbx+TEB_SP]")
|
||||||
lines.append("\tmov qword ptr [rcx+TEB_SP], rsp")
|
lines.append("\tmov qword ptr [rbx+TEB_SP], rsp")
|
||||||
lines.append("\tmov rsp, rbp")
|
lines.append("\tmov rsp, rbp")
|
||||||
|
|
||||||
# Allocate stack space for arguments
|
# Allocate stack space for arguments
|
||||||
@@ -881,21 +888,20 @@ def emit_cc_thunk64(f: FuncInfo | TypedefInfo, lines: List[str]):
|
|||||||
# Call into target
|
# Call into target
|
||||||
lines.append(f"\tcall {call_target}")
|
lines.append(f"\tcall {call_target}")
|
||||||
|
|
||||||
# Get current TEB
|
|
||||||
lines.append("\tmov rcx, fs:[currentThreadTeb@tpoff]")
|
|
||||||
|
|
||||||
# Restore host stack
|
# Restore host stack
|
||||||
lines.append("\tmov rsp, qword ptr [rcx+TEB_SP]")
|
lines.append("\tmov rsp, qword ptr [rbx+TEB_SP]")
|
||||||
lines.append("\tmov qword ptr [rcx+TEB_SP], rbp")
|
lines.append("\tmov qword ptr [rbx+TEB_SP], rbp")
|
||||||
|
|
||||||
# Jump to 32-bit mode
|
# Jump to 32-bit mode
|
||||||
lines.append("\tLJMP32")
|
lines.append("\tLJMP32 rbx")
|
||||||
|
|
||||||
# Setup FS selector
|
if sys.platform != "darwin":
|
||||||
lines.append("\tmov di, word ptr [ecx+TEB_FS_SEL]")
|
# Setup FS selector
|
||||||
lines.append("\tmov fs, di")
|
lines.append("\tmov di, word ptr [ebx+TEB_FS_SEL]")
|
||||||
|
lines.append("\tmov fs, di")
|
||||||
|
|
||||||
# Restore registers
|
# Restore registers
|
||||||
|
lines.append("\tpop ebx")
|
||||||
lines.append("\tpop edi")
|
lines.append("\tpop edi")
|
||||||
lines.append("\tpop esi")
|
lines.append("\tpop esi")
|
||||||
lines.append("\tpop ebp")
|
lines.append("\tpop ebp")
|
||||||
@@ -918,7 +924,7 @@ def emit_guest_to_host_thunks(
|
|||||||
lines: List[str], dll: str, funcs: Iterable[FuncInfo], arch: Arch
|
lines: List[str], dll: str, funcs: Iterable[FuncInfo], arch: Arch
|
||||||
) -> None:
|
) -> None:
|
||||||
for f in funcs:
|
for f in funcs:
|
||||||
thunk = f"thunk_{dll}_{f.name}"
|
thunk = f"{SYMBOL_PREFIX}thunk_{dll}_{f.name}"
|
||||||
lines.append("")
|
lines.append("")
|
||||||
lines.append(
|
lines.append(
|
||||||
f"# {f.qualified_ns}::{f.name} (source_cc={f.source_cc.name}, target_cc={f.target_cc.name}, variadic={f.variadic})"
|
f"# {f.qualified_ns}::{f.name} (source_cc={f.source_cc.name}, target_cc={f.target_cc.name}, variadic={f.variadic})"
|
||||||
@@ -933,17 +939,19 @@ def emit_guest_to_host_thunks(
|
|||||||
details.append(f"sign_extended={arg.sign_extended}")
|
details.append(f"sign_extended={arg.sign_extended}")
|
||||||
lines.append(f"\t# Arg {i} ({', '.join(details)})")
|
lines.append(f"\t# Arg {i} ({', '.join(details)})")
|
||||||
lines.append(f".globl {thunk}")
|
lines.append(f".globl {thunk}")
|
||||||
lines.append(f".type {thunk}, @function")
|
if sys.platform != "darwin":
|
||||||
|
lines.append(f".type {thunk}, @function")
|
||||||
lines.append(f"{thunk}:")
|
lines.append(f"{thunk}:")
|
||||||
emit_cc_thunk(f, lines, arch)
|
emit_cc_thunk(f, lines, arch)
|
||||||
lines.append(f".size {thunk}, .-{thunk}")
|
if sys.platform != "darwin":
|
||||||
|
lines.append(f".size {thunk}, .-{thunk}")
|
||||||
|
|
||||||
|
|
||||||
def emit_host_to_guest_thunks(
|
def emit_host_to_guest_thunks(
|
||||||
lines: List[str], typedefs: Iterable[TypedefInfo], arch: Arch
|
lines: List[str], typedefs: Iterable[TypedefInfo], arch: Arch
|
||||||
) -> None:
|
) -> None:
|
||||||
for f in typedefs:
|
for f in typedefs:
|
||||||
thunk = f"call_{f.name}"
|
thunk = f"{SYMBOL_PREFIX}call_{f.name}"
|
||||||
lines.append("")
|
lines.append("")
|
||||||
lines.append(
|
lines.append(
|
||||||
f"# {f.name} (target_cc={f.target_cc.name}, variadic={f.variadic})"
|
f"# {f.name} (target_cc={f.target_cc.name}, variadic={f.variadic})"
|
||||||
@@ -961,11 +969,16 @@ def emit_host_to_guest_thunks(
|
|||||||
# details.append(f"class={f.return_type.arg_class.value}")
|
# details.append(f"class={f.return_type.arg_class.value}")
|
||||||
# details.append(f"sign_extended={f.return_type.sign_extended}")
|
# details.append(f"sign_extended={f.return_type.sign_extended}")
|
||||||
# lines.append(f"\t# Ret ({', '.join(details)})")
|
# lines.append(f"\t# Ret ({', '.join(details)})")
|
||||||
lines.append(f".weak {thunk}")
|
if sys.platform == "darwin":
|
||||||
lines.append(f".type {thunk}, @function")
|
lines.append(f".globl {thunk}")
|
||||||
|
lines.append(f".weak_definition {thunk}")
|
||||||
|
else:
|
||||||
|
lines.append(f".weak {thunk}")
|
||||||
|
lines.append(f".type {thunk}, @function")
|
||||||
lines.append(f"{thunk}:")
|
lines.append(f"{thunk}:")
|
||||||
emit_cc_thunk(f, lines, arch)
|
emit_cc_thunk(f, lines, arch)
|
||||||
lines.append(f".size {thunk}, .-{thunk}")
|
if sys.platform != "darwin":
|
||||||
|
lines.append(f".size {thunk}, .-{thunk}")
|
||||||
|
|
||||||
|
|
||||||
def emit_header_mapping(
|
def emit_header_mapping(
|
||||||
@@ -1079,12 +1092,16 @@ def main() -> int:
|
|||||||
|
|
||||||
if args.arch == "x86":
|
if args.arch == "x86":
|
||||||
arch = Arch.X86
|
arch = Arch.X86
|
||||||
|
target = "i686-pc-linux-gnu"
|
||||||
elif args.arch == "x86_64":
|
elif args.arch == "x86_64":
|
||||||
arch = Arch.X86_64
|
arch = Arch.X86_64
|
||||||
|
if sys.platform == "darwin":
|
||||||
|
target = "x86_64-apple-darwin"
|
||||||
|
else:
|
||||||
|
target = "x86_64-pc-linux-gnu"
|
||||||
else:
|
else:
|
||||||
raise ValueError(f"Unsupported architecture: {args.arch}")
|
raise ValueError(f"Unsupported architecture: {args.arch}")
|
||||||
|
|
||||||
target = "i686-pc-linux-gnu" if args.arch == "x86" else "x86_64-pc-linux-gnu"
|
|
||||||
tu = parse_tu(args.headers, args.incs, target)
|
tu = parse_tu(args.headers, args.incs, target)
|
||||||
funcs = collect_functions(tu, args.ns, arch)
|
funcs = collect_functions(tu, args.ns, arch)
|
||||||
typedefs = collect_typedefs(tu, arch)
|
typedefs = collect_typedefs(tu, arch)
|
||||||
@@ -1097,7 +1114,8 @@ def main() -> int:
|
|||||||
lines: List[str] = []
|
lines: List[str] = []
|
||||||
lines.append("# Auto-generated thunks; DO NOT EDIT.")
|
lines.append("# Auto-generated thunks; DO NOT EDIT.")
|
||||||
lines.append('#include "macros.S"')
|
lines.append('#include "macros.S"')
|
||||||
lines.append('.section .note.GNU-stack, "", @progbits')
|
if sys.platform != "darwin":
|
||||||
|
lines.append('.section .note.GNU-stack, "", @progbits')
|
||||||
lines.append(".text")
|
lines.append(".text")
|
||||||
|
|
||||||
emit_guest_to_host_thunks(lines, args.dll, funcs, arch)
|
emit_guest_to_host_thunks(lines, args.dll, funcs, arch)
|
||||||
|
|||||||
Reference in New Issue
Block a user