mirror of
https://github.com/decompals/wibo.git
synced 2025-12-12 06:45:05 +00:00
Experimental 64-bit host support
This commit is contained in:
@@ -1,10 +1,5 @@
|
|||||||
cmake_minimum_required(VERSION 3.13)
|
cmake_minimum_required(VERSION 3.13)
|
||||||
|
|
||||||
set(CMAKE_C_FLAGS_INIT "-m32")
|
|
||||||
set(CMAKE_CXX_FLAGS_INIT "-m32 -fno-exceptions -fno-rtti")
|
|
||||||
set(CMAKE_EXE_LINKER_FLAGS_INIT "-m32")
|
|
||||||
set(CMAKE_SHARED_LINKER_FLAGS_INIT "-m32")
|
|
||||||
|
|
||||||
project(wibo LANGUAGES ASM C CXX)
|
project(wibo LANGUAGES ASM C CXX)
|
||||||
|
|
||||||
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")
|
||||||
@@ -46,11 +41,21 @@ configure_file(
|
|||||||
@ONLY
|
@ONLY
|
||||||
)
|
)
|
||||||
|
|
||||||
|
option(WIBO_64 "Build wibo for 64-bit host" OFF)
|
||||||
option(WIBO_ENABLE_FIXTURE_TESTS "Enable Win32 fixture tests (requires i686-w64-mingw32)" ON)
|
option(WIBO_ENABLE_FIXTURE_TESTS "Enable Win32 fixture tests (requires i686-w64-mingw32)" ON)
|
||||||
option(WIBO_ENABLE_LIBURING "Enable liburing for asynchronous I/O" OFF)
|
option(WIBO_ENABLE_LIBURING "Enable liburing for asynchronous I/O" OFF)
|
||||||
set(WIBO_ENABLE_LTO "AUTO" CACHE STRING "Enable link-time optimization (LTO)")
|
set(WIBO_ENABLE_LTO "AUTO" CACHE STRING "Enable link-time optimization (LTO)")
|
||||||
set_property(CACHE WIBO_ENABLE_LTO PROPERTY STRINGS "AUTO" "ON" "OFF")
|
set_property(CACHE WIBO_ENABLE_LTO PROPERTY STRINGS "AUTO" "ON" "OFF")
|
||||||
|
|
||||||
|
add_compile_options(
|
||||||
|
$<IF:$<BOOL:${WIBO_64}>,-m64,-m32>
|
||||||
|
$<$<COMPILE_LANGUAGE:CXX>:-fno-exceptions>
|
||||||
|
$<$<COMPILE_LANGUAGE:CXX>:-fno-rtti>
|
||||||
|
)
|
||||||
|
add_link_options(
|
||||||
|
$<IF:$<BOOL:${WIBO_64}>,-m64,-m32>
|
||||||
|
)
|
||||||
|
|
||||||
if (WIBO_ENABLE_LTO STREQUAL "AUTO")
|
if (WIBO_ENABLE_LTO STREQUAL "AUTO")
|
||||||
if (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
|
if (CMAKE_BUILD_TYPE STREQUAL "Release" OR CMAKE_BUILD_TYPE STREQUAL "MinSizeRel")
|
||||||
include(CheckIPOSupported)
|
include(CheckIPOSupported)
|
||||||
@@ -88,6 +93,10 @@ 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)
|
target_compile_definitions(mimalloc-obj PRIVATE MI_USE_BUILTIN_THREAD_POINTER=1)
|
||||||
|
if (WIBO_64)
|
||||||
|
# Disable a noisy warning on startup
|
||||||
|
target_compile_definitions(mimalloc-obj PRIVATE MI_DEBUG=0)
|
||||||
|
endif()
|
||||||
|
|
||||||
if (WIBO_ENABLE_LIBURING)
|
if (WIBO_ENABLE_LIBURING)
|
||||||
FetchContent_Declare(
|
FetchContent_Declare(
|
||||||
@@ -126,12 +135,12 @@ endif()
|
|||||||
|
|
||||||
add_executable(wibo
|
add_executable(wibo
|
||||||
dll/advapi32.cpp
|
dll/advapi32.cpp
|
||||||
|
dll/advapi32/md5.c
|
||||||
dll/advapi32/processthreadsapi.cpp
|
dll/advapi32/processthreadsapi.cpp
|
||||||
dll/advapi32/securitybaseapi.cpp
|
dll/advapi32/securitybaseapi.cpp
|
||||||
dll/advapi32/winbase.cpp
|
dll/advapi32/winbase.cpp
|
||||||
dll/advapi32/wincrypt.cpp
|
dll/advapi32/wincrypt.cpp
|
||||||
dll/advapi32/winreg.cpp
|
dll/advapi32/winreg.cpp
|
||||||
dll/advapi32/md5.c
|
|
||||||
dll/bcrypt.cpp
|
dll/bcrypt.cpp
|
||||||
dll/crt.cpp
|
dll/crt.cpp
|
||||||
dll/kernel32.cpp
|
dll/kernel32.cpp
|
||||||
@@ -144,8 +153,8 @@ add_executable(wibo
|
|||||||
dll/kernel32/interlockedapi.cpp
|
dll/kernel32/interlockedapi.cpp
|
||||||
dll/kernel32/ioapiset.cpp
|
dll/kernel32/ioapiset.cpp
|
||||||
dll/kernel32/libloaderapi.cpp
|
dll/kernel32/libloaderapi.cpp
|
||||||
dll/kernel32/namedpipeapi.cpp
|
|
||||||
dll/kernel32/memoryapi.cpp
|
dll/kernel32/memoryapi.cpp
|
||||||
|
dll/kernel32/namedpipeapi.cpp
|
||||||
dll/kernel32/processenv.cpp
|
dll/kernel32/processenv.cpp
|
||||||
dll/kernel32/processthreadsapi.cpp
|
dll/kernel32/processthreadsapi.cpp
|
||||||
dll/kernel32/profileapi.cpp
|
dll/kernel32/profileapi.cpp
|
||||||
@@ -162,8 +171,8 @@ add_executable(wibo
|
|||||||
dll/mscoree.cpp
|
dll/mscoree.cpp
|
||||||
dll/msvcrt.cpp
|
dll/msvcrt.cpp
|
||||||
dll/ntdll.cpp
|
dll/ntdll.cpp
|
||||||
dll/rpcrt4.cpp
|
|
||||||
dll/ole32.cpp
|
dll/ole32.cpp
|
||||||
|
dll/rpcrt4.cpp
|
||||||
dll/user32.cpp
|
dll/user32.cpp
|
||||||
dll/vcruntime.cpp
|
dll/vcruntime.cpp
|
||||||
dll/version.cpp
|
dll/version.cpp
|
||||||
@@ -173,21 +182,22 @@ add_executable(wibo
|
|||||||
src/errors.cpp
|
src/errors.cpp
|
||||||
src/files.cpp
|
src/files.cpp
|
||||||
src/handles.cpp
|
src/handles.cpp
|
||||||
src/loader.cpp
|
|
||||||
src/heap.cpp
|
src/heap.cpp
|
||||||
|
src/loader.cpp
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/modules.cpp
|
src/modules.cpp
|
||||||
src/processes.cpp
|
src/processes.cpp
|
||||||
src/resources.cpp
|
src/resources.cpp
|
||||||
|
src/setup.S
|
||||||
src/strutil.cpp
|
src/strutil.cpp
|
||||||
src/tls.cpp
|
src/tls.cpp
|
||||||
)
|
)
|
||||||
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=0x90000000)
|
target_link_options(wibo PRIVATE -no-pie -Wl,--image-base=0x70000000)
|
||||||
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
target_compile_options(wibo PRIVATE -fno-pie -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})
|
||||||
@@ -242,15 +252,17 @@ function(wibo_codegen_module)
|
|||||||
--dll ${module_NAME}
|
--dll ${module_NAME}
|
||||||
--headers ${module_HEADERS}
|
--headers ${module_HEADERS}
|
||||||
--namespace ${module_NAME}
|
--namespace ${module_NAME}
|
||||||
--arch x86
|
--arch $<IF:$<BOOL:${WIBO_64}>,x86_64,x86>
|
||||||
--out-asm ${out_asm}
|
--out-asm ${out_asm}
|
||||||
--out-hdr ${out_hdr}
|
--out-hdr ${out_hdr}
|
||||||
-I ${CMAKE_CURRENT_SOURCE_DIR}
|
-I ${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
-I ${CMAKE_CURRENT_SOURCE_DIR}/dll
|
-I ${CMAKE_CURRENT_SOURCE_DIR}/dll
|
||||||
-I ${CMAKE_CURRENT_SOURCE_DIR}/src
|
-I ${CMAKE_CURRENT_SOURCE_DIR}/src
|
||||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/gen_trampolines.py ${module_HEADERS})
|
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/tools/gen_trampolines.py
|
||||||
|
${module_HEADERS}
|
||||||
|
)
|
||||||
target_sources(wibo PRIVATE ${out_asm})
|
target_sources(wibo PRIVATE ${out_asm})
|
||||||
set_source_files_properties(${out_asm} PROPERTIES COMPILE_FLAGS "-m32")
|
set_source_files_properties(${out_asm} PROPERTIES COMPILE_FLAGS $<IF:$<BOOL:${WIBO_64}>,-m64,-m32>)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
wibo_codegen_module(NAME advapi32 HEADERS
|
wibo_codegen_module(NAME advapi32 HEADERS
|
||||||
|
|||||||
@@ -53,6 +53,46 @@
|
|||||||
"cacheVariables": {
|
"cacheVariables": {
|
||||||
"CMAKE_BUILD_TYPE": "Release"
|
"CMAKE_BUILD_TYPE": "Release"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "debug64",
|
||||||
|
"displayName": "Debug (64-bit)",
|
||||||
|
"inherits": ["ninja-base"],
|
||||||
|
"binaryDir": "${sourceDir}/build/debug64",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Debug",
|
||||||
|
"WIBO_64": "ON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "release64",
|
||||||
|
"displayName": "Release (64-bit)",
|
||||||
|
"inherits": ["ninja-base"],
|
||||||
|
"binaryDir": "${sourceDir}/build/release64",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Release",
|
||||||
|
"WIBO_64": "ON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "debug64-clang",
|
||||||
|
"displayName": "Debug (64-bit, Clang)",
|
||||||
|
"inherits": ["ninja-base", "clang-base"],
|
||||||
|
"binaryDir": "${sourceDir}/build/debug64-clang",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Debug",
|
||||||
|
"WIBO_64": "ON"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "release64-clang",
|
||||||
|
"displayName": "Release (64-bit, Clang)",
|
||||||
|
"inherits": ["ninja-base", "clang-base"],
|
||||||
|
"binaryDir": "${sourceDir}/build/release64-clang",
|
||||||
|
"cacheVariables": {
|
||||||
|
"CMAKE_BUILD_TYPE": "Release",
|
||||||
|
"WIBO_64": "ON"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"buildPresets": [
|
"buildPresets": [
|
||||||
@@ -83,6 +123,34 @@
|
|||||||
"configurePreset": "release-clang",
|
"configurePreset": "release-clang",
|
||||||
"targets": ["wibo", "wibo_test_fixtures"],
|
"targets": ["wibo", "wibo_test_fixtures"],
|
||||||
"configuration": "Release"
|
"configuration": "Release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "debug64",
|
||||||
|
"displayName": "Build (Debug, 64-bit)",
|
||||||
|
"configurePreset": "debug64",
|
||||||
|
"targets": ["wibo", "wibo_test_fixtures"],
|
||||||
|
"configuration": "Debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "release64",
|
||||||
|
"displayName": "Build (Release, 64-bit)",
|
||||||
|
"configurePreset": "release64",
|
||||||
|
"targets": ["wibo", "wibo_test_fixtures"],
|
||||||
|
"configuration": "Release"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "debug64-clang",
|
||||||
|
"displayName": "Build (Debug, 64-bit, Clang)",
|
||||||
|
"configurePreset": "debug64-clang",
|
||||||
|
"targets": ["wibo", "wibo_test_fixtures"],
|
||||||
|
"configuration": "Debug"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "release64-clang",
|
||||||
|
"displayName": "Build (Release, 64-bit, Clang)",
|
||||||
|
"configurePreset": "release64-clang",
|
||||||
|
"targets": ["wibo", "wibo_test_fixtures"],
|
||||||
|
"configuration": "Release"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"testPresets": [
|
"testPresets": [
|
||||||
@@ -125,6 +193,46 @@
|
|||||||
"outputOnFailure": true,
|
"outputOnFailure": true,
|
||||||
"shortProgress": true
|
"shortProgress": true
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "debug64",
|
||||||
|
"displayName": "Run tests (Debug, 64-bit)",
|
||||||
|
"configurePreset": "debug64",
|
||||||
|
"configuration": "Debug",
|
||||||
|
"output": {
|
||||||
|
"outputOnFailure": true,
|
||||||
|
"shortProgress": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "release64",
|
||||||
|
"displayName": "Run tests (Release, 64-bit)",
|
||||||
|
"configurePreset": "release64",
|
||||||
|
"configuration": "Release",
|
||||||
|
"output": {
|
||||||
|
"outputOnFailure": true,
|
||||||
|
"shortProgress": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "debug64-clang",
|
||||||
|
"displayName": "Run tests (Debug, 64-bit, Clang)",
|
||||||
|
"configurePreset": "debug64-clang",
|
||||||
|
"configuration": "Debug",
|
||||||
|
"output": {
|
||||||
|
"outputOnFailure": true,
|
||||||
|
"shortProgress": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "release64-clang",
|
||||||
|
"displayName": "Run tests (Release, 64-bit, Clang)",
|
||||||
|
"configurePreset": "release64-clang",
|
||||||
|
"configuration": "Release",
|
||||||
|
"output": {
|
||||||
|
"outputOnFailure": true,
|
||||||
|
"shortProgress": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,8 +6,6 @@
|
|||||||
|
|
||||||
constexpr DWORD SECURITY_LOCAL_SYSTEM_RID = 18;
|
constexpr DWORD SECURITY_LOCAL_SYSTEM_RID = 18;
|
||||||
|
|
||||||
constexpr BYTE kNtAuthority[6] = {0, 0, 0, 0, 0, 5};
|
|
||||||
|
|
||||||
struct TokenObject : ObjectBase {
|
struct TokenObject : ObjectBase {
|
||||||
static constexpr ObjectType kType = ObjectType::Token;
|
static constexpr ObjectType kType = ObjectType::Token;
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "handles.h"
|
#include "handles.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "kernel32/internal.h"
|
#include "kernel32/internal.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -13,6 +14,8 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
constexpr BYTE kNtAuthority[6] = {0, 0, 0, 0, 0, 5};
|
||||||
|
|
||||||
constexpr size_t kAceAlignment = 4;
|
constexpr size_t kAceAlignment = 4;
|
||||||
constexpr DWORD ERROR_REVISION_MISMATCH = 1306;
|
constexpr DWORD ERROR_REVISION_MISMATCH = 1306;
|
||||||
constexpr DWORD ERROR_INVALID_ACL = 1336;
|
constexpr DWORD ERROR_INVALID_ACL = 1336;
|
||||||
@@ -202,14 +205,14 @@ BOOL WINAPI AddAccessAllowedAce(PACL pAcl, DWORD dwAceRevision, DWORD AccessMask
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI FindFirstFreeAce(PACL pAcl, LPVOID *pAce) {
|
BOOL WINAPI FindFirstFreeAce(PACL pAcl, GUEST_PTR *pAce) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("FindFirstFreeAce(%p, %p)\n", pAcl, pAce);
|
DEBUG_LOG("FindFirstFreeAce(%p, %p)\n", pAcl, pAce);
|
||||||
if (!pAce) {
|
if (!pAce) {
|
||||||
kernel32::setLastError(ERROR_INVALID_PARAMETER);
|
kernel32::setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
*pAce = nullptr;
|
*pAce = GUEST_NULL;
|
||||||
if (!pAcl) {
|
if (!pAcl) {
|
||||||
kernel32::setLastError(ERROR_INVALID_PARAMETER);
|
kernel32::setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
@@ -220,13 +223,13 @@ BOOL WINAPI FindFirstFreeAce(PACL pAcl, LPVOID *pAce) {
|
|||||||
kernel32::setLastError(ERROR_INVALID_ACL);
|
kernel32::setLastError(ERROR_INVALID_ACL);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
*pAce = reinterpret_cast<BYTE *>(pAcl) + used;
|
*pAce = toGuestPtr(reinterpret_cast<BYTE *>(pAcl) + used);
|
||||||
pAcl->AclSize = static_cast<WORD>(std::max<size_t>(pAcl->AclSize, used));
|
pAcl->AclSize = static_cast<WORD>(std::max<size_t>(pAcl->AclSize, used));
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl,
|
BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, GUEST_PTR *pDacl,
|
||||||
LPBOOL lpbDaclDefaulted) {
|
LPBOOL lpbDaclDefaulted) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("GetSecurityDescriptorDacl(%p, %p, %p, %p)\n", pSecurityDescriptor, lpbDaclPresent, pDacl,
|
DEBUG_LOG("GetSecurityDescriptorDacl(%p, %p, %p, %p)\n", pSecurityDescriptor, lpbDaclPresent, pDacl,
|
||||||
lpbDaclDefaulted);
|
lpbDaclDefaulted);
|
||||||
@@ -246,7 +249,7 @@ BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|||||||
*lpbDaclPresent = hasDacl;
|
*lpbDaclPresent = hasDacl;
|
||||||
if (!hasDacl) {
|
if (!hasDacl) {
|
||||||
if (pDacl) {
|
if (pDacl) {
|
||||||
*pDacl = nullptr;
|
*pDacl = GUEST_NULL;
|
||||||
}
|
}
|
||||||
if (lpbDaclDefaulted) {
|
if (lpbDaclDefaulted) {
|
||||||
*lpbDaclDefaulted = FALSE;
|
*lpbDaclDefaulted = FALSE;
|
||||||
@@ -315,7 +318,7 @@ BOOL WINAPI ImpersonateLoggedOnUser(HANDLE hToken) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, void *lpTokenAttributes,
|
BOOL WINAPI DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, void *lpTokenAttributes,
|
||||||
DWORD ImpersonationLevel, DWORD TokenType, PHANDLE phNewToken) {
|
DWORD ImpersonationLevel, DWORD TokenType, PHANDLE phNewToken) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("DuplicateTokenEx(%p, 0x%x, %p, %u, %u, %p)\n", hExistingToken, dwDesiredAccess, lpTokenAttributes,
|
DEBUG_LOG("DuplicateTokenEx(%p, 0x%x, %p, %u, %u, %p)\n", hExistingToken, dwDesiredAccess, lpTokenAttributes,
|
||||||
ImpersonationLevel, TokenType, phNewToken);
|
ImpersonationLevel, TokenType, phNewToken);
|
||||||
@@ -399,7 +402,7 @@ BOOL WINAPI EqualSid(PSID pSid1, PSID pSid2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation,
|
BOOL WINAPI SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation,
|
||||||
PSECURITY_DESCRIPTOR SecurityDescriptor) {
|
PSECURITY_DESCRIPTOR SecurityDescriptor) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("STUB: SetKernelObjectSecurity(%p, 0x%x, %p)\n", Handle, SecurityInformation, SecurityDescriptor);
|
DEBUG_LOG("STUB: SetKernelObjectSecurity(%p, 0x%x, %p)\n", Handle, SecurityInformation, SecurityDescriptor);
|
||||||
(void)SecurityInformation;
|
(void)SecurityInformation;
|
||||||
@@ -425,15 +428,15 @@ BOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescripto
|
|||||||
pSecurityDescriptor->Revision = static_cast<BYTE>(dwRevision);
|
pSecurityDescriptor->Revision = static_cast<BYTE>(dwRevision);
|
||||||
pSecurityDescriptor->Sbz1 = 0;
|
pSecurityDescriptor->Sbz1 = 0;
|
||||||
pSecurityDescriptor->Control = 0;
|
pSecurityDescriptor->Control = 0;
|
||||||
pSecurityDescriptor->Owner = nullptr;
|
pSecurityDescriptor->Owner = GUEST_NULL;
|
||||||
pSecurityDescriptor->Group = nullptr;
|
pSecurityDescriptor->Group = GUEST_NULL;
|
||||||
pSecurityDescriptor->Sacl = nullptr;
|
pSecurityDescriptor->Sacl = GUEST_NULL;
|
||||||
pSecurityDescriptor->Dacl = nullptr;
|
pSecurityDescriptor->Dacl = GUEST_NULL;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl,
|
BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl,
|
||||||
BOOL bDaclDefaulted) {
|
BOOL bDaclDefaulted) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("SetSecurityDescriptorDacl(%p, %u, %p, %u)\n", pSecurityDescriptor, bDaclPresent, pDacl, bDaclDefaulted);
|
DEBUG_LOG("SetSecurityDescriptorDacl(%p, %u, %p, %u)\n", pSecurityDescriptor, bDaclPresent, pDacl, bDaclDefaulted);
|
||||||
if (!pSecurityDescriptor || pSecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
|
if (!pSecurityDescriptor || pSecurityDescriptor->Revision != SECURITY_DESCRIPTOR_REVISION) {
|
||||||
@@ -446,16 +449,16 @@ BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|||||||
if (bDaclDefaulted) {
|
if (bDaclDefaulted) {
|
||||||
control = static_cast<WORD>(control | SE_DACL_DEFAULTED);
|
control = static_cast<WORD>(control | SE_DACL_DEFAULTED);
|
||||||
}
|
}
|
||||||
pSecurityDescriptor->Dacl = pDacl;
|
pSecurityDescriptor->Dacl = toGuestPtr(pDacl);
|
||||||
} else {
|
} else {
|
||||||
pSecurityDescriptor->Dacl = nullptr;
|
pSecurityDescriptor->Dacl = GUEST_NULL;
|
||||||
}
|
}
|
||||||
pSecurityDescriptor->Control = control;
|
pSecurityDescriptor->Control = control;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
|
BOOL WINAPI GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
|
||||||
LPVOID TokenInformation, DWORD TokenInformationLength, LPDWORD ReturnLength) {
|
LPVOID TokenInformation, DWORD TokenInformationLength, LPDWORD ReturnLength) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("STUB: GetTokenInformation(%p, %u, %p, %u, %p)\n", TokenHandle, TokenInformationClass, TokenInformation,
|
DEBUG_LOG("STUB: GetTokenInformation(%p, %u, %p, %u, %p)\n", TokenHandle, TokenInformationClass, TokenInformation,
|
||||||
TokenInformationLength, ReturnLength);
|
TokenInformationLength, ReturnLength);
|
||||||
@@ -535,7 +538,7 @@ BOOL WINAPI GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS Toke
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState,
|
BOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState,
|
||||||
DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, LPDWORD ReturnLength) {
|
DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, LPDWORD ReturnLength) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("AdjustTokenPrivileges(%p, %u, %p, %u, %p, %p)\n", TokenHandle, DisableAllPrivileges, NewState,
|
DEBUG_LOG("AdjustTokenPrivileges(%p, %u, %p, %u, %p, %p)\n", TokenHandle, DisableAllPrivileges, NewState,
|
||||||
BufferLength, PreviousState, ReturnLength);
|
BufferLength, PreviousState, ReturnLength);
|
||||||
@@ -549,7 +552,7 @@ BOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges,
|
|||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI SetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
|
BOOL WINAPI SetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
|
||||||
LPVOID TokenInformation, DWORD TokenInformationLength) {
|
LPVOID TokenInformation, DWORD TokenInformationLength) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("STUB: SetTokenInformation(%p, %u, %p, %u)\n", TokenHandle, TokenInformationClass, TokenInformation,
|
DEBUG_LOG("STUB: SetTokenInformation(%p, %u, %p, %u)\n", TokenHandle, TokenInformationClass, TokenInformation,
|
||||||
TokenInformationLength);
|
TokenInformationLength);
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ struct SECURITY_DESCRIPTOR {
|
|||||||
BYTE Revision;
|
BYTE Revision;
|
||||||
BYTE Sbz1;
|
BYTE Sbz1;
|
||||||
WORD Control;
|
WORD Control;
|
||||||
void *Owner;
|
GUEST_PTR Owner;
|
||||||
void *Group;
|
GUEST_PTR Group;
|
||||||
ACL *Sacl;
|
GUEST_PTR Sacl;
|
||||||
ACL *Dacl;
|
GUEST_PTR Dacl;
|
||||||
};
|
};
|
||||||
|
|
||||||
using PSECURITY_DESCRIPTOR = SECURITY_DESCRIPTOR *;
|
using PSECURITY_DESCRIPTOR = SECURITY_DESCRIPTOR *;
|
||||||
@@ -85,28 +85,28 @@ namespace advapi32 {
|
|||||||
|
|
||||||
BOOL WINAPI InitializeAcl(PACL pAcl, DWORD nAclLength, DWORD dwAclRevision);
|
BOOL WINAPI InitializeAcl(PACL pAcl, DWORD nAclLength, DWORD dwAclRevision);
|
||||||
BOOL WINAPI AddAccessAllowedAce(PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid);
|
BOOL WINAPI AddAccessAllowedAce(PACL pAcl, DWORD dwAceRevision, DWORD AccessMask, PSID pSid);
|
||||||
BOOL WINAPI FindFirstFreeAce(PACL pAcl, LPVOID *pAce);
|
BOOL WINAPI FindFirstFreeAce(PACL pAcl, GUEST_PTR *pAce);
|
||||||
PSID_IDENTIFIER_AUTHORITY WINAPI GetSidIdentifierAuthority(PSID pSid);
|
PSID_IDENTIFIER_AUTHORITY WINAPI GetSidIdentifierAuthority(PSID pSid);
|
||||||
PUCHAR WINAPI GetSidSubAuthorityCount(PSID pSid);
|
PUCHAR WINAPI GetSidSubAuthorityCount(PSID pSid);
|
||||||
PDWORD WINAPI GetSidSubAuthority(PSID pSid, DWORD nSubAuthority);
|
PDWORD WINAPI GetSidSubAuthority(PSID pSid, DWORD nSubAuthority);
|
||||||
BOOL WINAPI ImpersonateLoggedOnUser(HANDLE hToken);
|
BOOL WINAPI ImpersonateLoggedOnUser(HANDLE hToken);
|
||||||
BOOL WINAPI DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, void *lpTokenAttributes,
|
BOOL WINAPI DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, void *lpTokenAttributes,
|
||||||
DWORD ImpersonationLevel, DWORD TokenType, PHANDLE phNewToken);
|
DWORD ImpersonationLevel, DWORD TokenType, PHANDLE phNewToken);
|
||||||
BOOL WINAPI CopySid(DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid);
|
BOOL WINAPI CopySid(DWORD nDestinationSidLength, PSID pDestinationSid, PSID pSourceSid);
|
||||||
BOOL WINAPI InitializeSid(PSID sid, PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount);
|
BOOL WINAPI InitializeSid(PSID sid, PSID_IDENTIFIER_AUTHORITY pIdentifierAuthority, BYTE nSubAuthorityCount);
|
||||||
BOOL WINAPI EqualSid(PSID pSid1, PSID pSid2);
|
BOOL WINAPI EqualSid(PSID pSid1, PSID pSid2);
|
||||||
BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, PACL *pDacl,
|
BOOL WINAPI GetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, LPBOOL lpbDaclPresent, GUEST_PTR *pDacl,
|
||||||
LPBOOL lpbDaclDefaulted);
|
LPBOOL lpbDaclDefaulted);
|
||||||
BOOL WINAPI SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation,
|
BOOL WINAPI SetKernelObjectSecurity(HANDLE Handle, SECURITY_INFORMATION SecurityInformation,
|
||||||
PSECURITY_DESCRIPTOR SecurityDescriptor);
|
PSECURITY_DESCRIPTOR SecurityDescriptor);
|
||||||
BOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision);
|
BOOL WINAPI InitializeSecurityDescriptor(PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD dwRevision);
|
||||||
BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl,
|
BOOL WINAPI SetSecurityDescriptorDacl(PSECURITY_DESCRIPTOR pSecurityDescriptor, BOOL bDaclPresent, PACL pDacl,
|
||||||
BOOL bDaclDefaulted);
|
BOOL bDaclDefaulted);
|
||||||
BOOL WINAPI GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
|
BOOL WINAPI GetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
|
||||||
LPVOID TokenInformation, DWORD TokenInformationLength, LPDWORD ReturnLength);
|
LPVOID TokenInformation, DWORD TokenInformationLength, LPDWORD ReturnLength);
|
||||||
BOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState,
|
BOOL WINAPI AdjustTokenPrivileges(HANDLE TokenHandle, BOOL DisableAllPrivileges, PTOKEN_PRIVILEGES NewState,
|
||||||
DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, LPDWORD ReturnLength);
|
DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, LPDWORD ReturnLength);
|
||||||
BOOL WINAPI SetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
|
BOOL WINAPI SetTokenInformation(HANDLE TokenHandle, TOKEN_INFORMATION_CLASS TokenInformationClass,
|
||||||
LPVOID TokenInformation, DWORD TokenInformationLength);
|
LPVOID TokenInformation, DWORD TokenInformationLength);
|
||||||
|
|
||||||
} // namespace advapi32
|
} // namespace advapi32
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ namespace {
|
|||||||
|
|
||||||
constexpr WCHAR kAccountSystem[] = {u'S', u'Y', u'S', u'T', u'E', u'M', u'\0'};
|
constexpr WCHAR kAccountSystem[] = {u'S', u'Y', u'S', u'T', u'E', u'M', u'\0'};
|
||||||
constexpr WCHAR kDomainNtAuthority[] = {u'N', u'T', u' ', u'A', u'U', u'T', u'H', u'O', u'R', u'I', u'T', u'Y', u'\0'};
|
constexpr WCHAR kDomainNtAuthority[] = {u'N', u'T', u' ', u'A', u'U', u'T', u'H', u'O', u'R', u'I', u'T', u'Y', u'\0'};
|
||||||
|
constexpr BYTE kNtAuthority[6] = {0, 0, 0, 0, 0, 5};
|
||||||
|
|
||||||
std::mutex g_privilegeMapMutex;
|
std::mutex g_privilegeMapMutex;
|
||||||
std::unordered_map<std::string, LUID> g_privilegeLuidCache;
|
std::unordered_map<std::string, LUID> g_privilegeLuidCache;
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ enum SID_NAME_USE : DWORD {
|
|||||||
|
|
||||||
namespace advapi32 {
|
namespace advapi32 {
|
||||||
|
|
||||||
BOOL WINAPI LookupAccountSidW(LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName,
|
BOOL WINAPI LookupAccountSidW(LPCWSTR lpSystemName, PSID Sid, LPWSTR Name, LPDWORD cchName, LPWSTR ReferencedDomainName,
|
||||||
LPWSTR ReferencedDomainName, LPDWORD cchReferencedDomainName, SID_NAME_USE *peUse);
|
LPDWORD cchReferencedDomainName, SID_NAME_USE *peUse);
|
||||||
BOOL WINAPI LookupPrivilegeValueA(LPCSTR lpSystemName, LPCSTR lpName, PLUID lpLuid);
|
BOOL WINAPI LookupPrivilegeValueA(LPCSTR lpSystemName, LPCSTR lpName, PLUID lpLuid);
|
||||||
BOOL WINAPI LookupPrivilegeValueW(LPCWSTR lpSystemName, LPCWSTR lpName, PLUID lpLuid);
|
BOOL WINAPI LookupPrivilegeValueW(LPCWSTR lpSystemName, LPCWSTR lpName, PLUID lpLuid);
|
||||||
BOOL WINAPI GetUserNameA(LPSTR lpBuffer, LPDWORD pcbBuffer);
|
BOOL WINAPI GetUserNameA(LPSTR lpBuffer, LPDWORD pcbBuffer);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ namespace advapi32 {
|
|||||||
|
|
||||||
BOOL WINAPI CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags);
|
BOOL WINAPI CryptReleaseContext(HCRYPTPROV hProv, DWORD dwFlags);
|
||||||
BOOL WINAPI CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR pszContainer, LPCWSTR pszProvider, DWORD dwProvType,
|
BOOL WINAPI CryptAcquireContextW(HCRYPTPROV *phProv, LPCWSTR pszContainer, LPCWSTR pszProvider, DWORD dwProvType,
|
||||||
DWORD dwFlags);
|
DWORD dwFlags);
|
||||||
BOOL WINAPI CryptGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer);
|
BOOL WINAPI CryptGenRandom(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer);
|
||||||
BOOL WINAPI CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash);
|
BOOL WINAPI CryptCreateHash(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *phHash);
|
||||||
BOOL WINAPI CryptHashData(HCRYPTHASH hHash, const BYTE *pbData, DWORD dwDataLen, DWORD dwFlags);
|
BOOL WINAPI CryptHashData(HCRYPTHASH hHash, const BYTE *pbData, DWORD dwDataLen, DWORD dwFlags);
|
||||||
|
|||||||
@@ -29,17 +29,17 @@ struct RegistryKeyObject : ObjectBase {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct PredefinedKeyInfo {
|
struct PredefinedKeyInfo {
|
||||||
uintptr_t value;
|
HKEY value;
|
||||||
const char16_t *name;
|
const char16_t *name;
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr PredefinedKeyInfo kPredefinedKeyInfos[] = {
|
constexpr PredefinedKeyInfo kPredefinedKeyInfos[] = {
|
||||||
{static_cast<uintptr_t>(0x80000000u), u"HKEY_CLASSES_ROOT"},
|
{static_cast<HKEY>(0x80000000u), u"HKEY_CLASSES_ROOT"},
|
||||||
{static_cast<uintptr_t>(0x80000001u), u"HKEY_CURRENT_USER"},
|
{static_cast<HKEY>(0x80000001u), u"HKEY_CURRENT_USER"},
|
||||||
{static_cast<uintptr_t>(0x80000002u), u"HKEY_LOCAL_MACHINE"},
|
{static_cast<HKEY>(0x80000002u), u"HKEY_LOCAL_MACHINE"},
|
||||||
{static_cast<uintptr_t>(0x80000003u), u"HKEY_USERS"},
|
{static_cast<HKEY>(0x80000003u), u"HKEY_USERS"},
|
||||||
{static_cast<uintptr_t>(0x80000004u), u"HKEY_PERFORMANCE_DATA"},
|
{static_cast<HKEY>(0x80000004u), u"HKEY_PERFORMANCE_DATA"},
|
||||||
{static_cast<uintptr_t>(0x80000005u), u"HKEY_CURRENT_CONFIG"},
|
{static_cast<HKEY>(0x80000005u), u"HKEY_CURRENT_CONFIG"},
|
||||||
};
|
};
|
||||||
|
|
||||||
constexpr size_t kPredefinedKeyCount = std::size(kPredefinedKeyInfos);
|
constexpr size_t kPredefinedKeyCount = std::size(kPredefinedKeyInfos);
|
||||||
@@ -82,7 +82,7 @@ std::u16string canonicalizeKeySegment(LPCWSTR input) {
|
|||||||
return canonicalizeKeySegment(wide);
|
return canonicalizeKeySegment(wide);
|
||||||
}
|
}
|
||||||
|
|
||||||
Pin<RegistryKeyObject> predefinedHandleForValue(uintptr_t value) {
|
Pin<RegistryKeyObject> predefinedHandleForValue(HKEY value) {
|
||||||
static std::array<Pin<RegistryKeyObject>, kPredefinedKeyCount> g_predefinedHandles = [] {
|
static std::array<Pin<RegistryKeyObject>, kPredefinedKeyCount> g_predefinedHandles = [] {
|
||||||
std::array<Pin<RegistryKeyObject>, kPredefinedKeyCount> arr;
|
std::array<Pin<RegistryKeyObject>, kPredefinedKeyCount> arr;
|
||||||
for (size_t i = 0; i < kPredefinedKeyCount; ++i) {
|
for (size_t i = 0; i < kPredefinedKeyCount; ++i) {
|
||||||
@@ -101,11 +101,10 @@ Pin<RegistryKeyObject> predefinedHandleForValue(uintptr_t value) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Pin<RegistryKeyObject> handleDataFromHKeyLocked(HKEY hKey) {
|
Pin<RegistryKeyObject> handleDataFromHKeyLocked(HKEY hKey) {
|
||||||
uintptr_t raw = reinterpret_cast<uintptr_t>(hKey);
|
if (hKey == NO_HANDLE) {
|
||||||
if (raw == 0) {
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
if (auto predefined = predefinedHandleForValue(raw)) {
|
if (auto predefined = predefinedHandleForValue(hKey)) {
|
||||||
return predefined;
|
return predefined;
|
||||||
}
|
}
|
||||||
auto obj = wibo::handles().getAs<RegistryKeyObject>(hKey);
|
auto obj = wibo::handles().getAs<RegistryKeyObject>(hKey);
|
||||||
@@ -116,9 +115,8 @@ Pin<RegistryKeyObject> handleDataFromHKeyLocked(HKEY hKey) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool isPredefinedKeyHandle(HKEY hKey) {
|
bool isPredefinedKeyHandle(HKEY hKey) {
|
||||||
uintptr_t raw = reinterpret_cast<uintptr_t>(hKey);
|
|
||||||
return std::any_of(std::begin(kPredefinedKeyInfos), std::end(kPredefinedKeyInfos),
|
return std::any_of(std::begin(kPredefinedKeyInfos), std::end(kPredefinedKeyInfos),
|
||||||
[raw](const PredefinedKeyInfo &info) { return info.value == raw; });
|
[hKey](const PredefinedKeyInfo &info) { return info.value == hKey; });
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -139,7 +137,7 @@ LSTATUS WINAPI RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWS
|
|||||||
kernel32::setLastError(ERROR_INVALID_PARAMETER);
|
kernel32::setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return ERROR_INVALID_PARAMETER;
|
return ERROR_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
*phkResult = nullptr;
|
*phkResult = NO_HANDLE;
|
||||||
if (Reserved != 0) {
|
if (Reserved != 0) {
|
||||||
kernel32::setLastError(ERROR_INVALID_PARAMETER);
|
kernel32::setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return ERROR_INVALID_PARAMETER;
|
return ERROR_INVALID_PARAMETER;
|
||||||
@@ -220,7 +218,7 @@ LSTATUS WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSA
|
|||||||
kernel32::setLastError(ERROR_INVALID_PARAMETER);
|
kernel32::setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return ERROR_INVALID_PARAMETER;
|
return ERROR_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
*phkResult = nullptr;
|
*phkResult = NO_HANDLE;
|
||||||
if ((ulOptions & ~REG_OPTION_OPEN_LINK) != 0) {
|
if ((ulOptions & ~REG_OPTION_OPEN_LINK) != 0) {
|
||||||
kernel32::setLastError(ERROR_INVALID_PARAMETER);
|
kernel32::setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return ERROR_INVALID_PARAMETER;
|
return ERROR_INVALID_PARAMETER;
|
||||||
|
|||||||
@@ -34,21 +34,19 @@ constexpr REGSAM KEY_WOW64_32KEY = 0x00000200;
|
|||||||
namespace advapi32 {
|
namespace advapi32 {
|
||||||
|
|
||||||
LSTATUS WINAPI RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions,
|
LSTATUS WINAPI RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions,
|
||||||
REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult,
|
REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition);
|
||||||
LPDWORD lpdwDisposition);
|
|
||||||
LSTATUS WINAPI RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions,
|
LSTATUS WINAPI RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions,
|
||||||
REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult,
|
REGSAM samDesired, void *lpSecurityAttributes, PHKEY phkResult, LPDWORD lpdwDisposition);
|
||||||
LPDWORD lpdwDisposition);
|
|
||||||
LSTATUS WINAPI RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
|
LSTATUS WINAPI RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
|
||||||
LSTATUS WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
|
LSTATUS WINAPI RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult);
|
||||||
LSTATUS WINAPI RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData,
|
LSTATUS WINAPI RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData,
|
||||||
LPDWORD lpcbData);
|
LPDWORD lpcbData);
|
||||||
LSTATUS WINAPI RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData,
|
LSTATUS WINAPI RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, BYTE *lpData,
|
||||||
LPDWORD lpcbData);
|
LPDWORD lpcbData);
|
||||||
LSTATUS WINAPI RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved,
|
LSTATUS WINAPI RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved,
|
||||||
LPSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime);
|
LPSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime);
|
||||||
LSTATUS WINAPI RegEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved,
|
LSTATUS WINAPI RegEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcchName, LPDWORD lpReserved,
|
||||||
LPWSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime);
|
LPWSTR lpClass, LPDWORD lpcchClass, FILETIME *lpftLastWriteTime);
|
||||||
LSTATUS WINAPI RegCloseKey(HKEY hKey);
|
LSTATUS WINAPI RegCloseKey(HKEY hKey);
|
||||||
|
|
||||||
} // namespace advapi32
|
} // namespace advapi32
|
||||||
|
|||||||
133
dll/crt.cpp
133
dll/crt.cpp
@@ -6,6 +6,7 @@
|
|||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "kernel32/internal.h"
|
#include "kernel32/internal.h"
|
||||||
#include "modules.h"
|
#include "modules.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
@@ -42,24 +43,29 @@ int _fmode = 0;
|
|||||||
std::vector<_PVFV> atexitFuncs;
|
std::vector<_PVFV> atexitFuncs;
|
||||||
_invalid_parameter_handler invalidParameterHandler = nullptr;
|
_invalid_parameter_handler invalidParameterHandler = nullptr;
|
||||||
|
|
||||||
void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end) {
|
GUEST_PTR guestArgv = GUEST_NULL;
|
||||||
|
GUEST_PTR guestEnviron = GUEST_NULL;
|
||||||
|
|
||||||
|
void CDECL _initterm(GUEST_PTR *ppfn, GUEST_PTR *end) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("_initterm(%p, %p)\n", ppfn, end);
|
DEBUG_LOG("_initterm(%p, %p)\n", ppfn, end);
|
||||||
do {
|
do {
|
||||||
if (_PVFV pfn = *++ppfn) {
|
if (GUEST_PTR pfn = *++ppfn) {
|
||||||
DEBUG_LOG("-> calling %p\n", pfn);
|
DEBUG_LOG("-> calling %p\n", pfn);
|
||||||
call__PVFV(pfn);
|
auto fn = reinterpret_cast<_PVFV>(fromGuestPtr(pfn));
|
||||||
|
call__PVFV(fn);
|
||||||
}
|
}
|
||||||
} while (ppfn < end);
|
} while (ppfn < end);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end) {
|
int CDECL _initterm_e(GUEST_PTR *ppfn, GUEST_PTR *end) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("_initterm_e(%p, %p)\n", ppfn, end);
|
DEBUG_LOG("_initterm_e(%p, %p)\n", ppfn, end);
|
||||||
do {
|
do {
|
||||||
if (_PIFV pfn = *++ppfn) {
|
if (GUEST_PTR pfn = *++ppfn) {
|
||||||
DEBUG_LOG("-> calling %p\n", pfn);
|
DEBUG_LOG("-> calling %p\n", pfn);
|
||||||
int err = call__PIFV(pfn);
|
auto fn = reinterpret_cast<_PIFV>(fromGuestPtr(pfn));
|
||||||
|
int err = call__PIFV(fn);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
@@ -80,16 +86,16 @@ int CDECL _set_fmode(int mode) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int *CDECL __p__commode() {
|
GUEST_PTR CDECL __p__commode() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("__p__commode()\n");
|
DEBUG_LOG("__p__commode()\n");
|
||||||
return &_commode;
|
return toGuestPtr(&_commode);
|
||||||
}
|
}
|
||||||
|
|
||||||
int *CDECL __p__fmode() {
|
GUEST_PTR CDECL __p__fmode() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("__p__fmode()\n");
|
DEBUG_LOG("__p__fmode()\n");
|
||||||
return &_fmode;
|
return toGuestPtr(&_fmode);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CDECL _crt_atexit(void (*func)()) {
|
int CDECL _crt_atexit(void (*func)()) {
|
||||||
@@ -137,28 +143,79 @@ int CDECL _set_new_mode(int newhandlermode) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char **CDECL _get_initial_narrow_environment() {
|
GUEST_PTR CDECL _get_initial_narrow_environment() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("_get_initial_narrow_environment()\n");
|
DEBUG_LOG("_get_initial_narrow_environment()\n");
|
||||||
return environ;
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
char ***CDECL __p__environ() {
|
GUEST_PTR CDECL __p__environ() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("__p__environ()\n");
|
DEBUG_LOG("__p__environ()\n");
|
||||||
return &environ;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
char ***CDECL __p___argv() {
|
GUEST_PTR CDECL __p___argv() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("__p___argv()\n");
|
DEBUG_LOG("__p___argv()\n");
|
||||||
return &wibo::argv;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
int *CDECL __p___argc() {
|
GUEST_PTR CDECL __p___argc() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("__p___argc()\n");
|
DEBUG_LOG("__p___argc()\n");
|
||||||
return &wibo::argc;
|
return toGuestPtr(&wibo::argc);
|
||||||
}
|
}
|
||||||
|
|
||||||
SIZE_T CDECL strlen(const char *str) {
|
SIZE_T CDECL strlen(const char *str) {
|
||||||
@@ -258,9 +315,9 @@ int CDECL _initialize_onexit_table(_onexit_table_t *table) {
|
|||||||
return -1;
|
return -1;
|
||||||
if (table->first != table->last)
|
if (table->first != table->last)
|
||||||
return 0;
|
return 0;
|
||||||
table->first = nullptr;
|
table->first = GUEST_NULL;
|
||||||
table->last = nullptr;
|
table->last = GUEST_NULL;
|
||||||
table->end = nullptr;
|
table->end = GUEST_NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -269,20 +326,23 @@ int CDECL _register_onexit_function(_onexit_table_t *table, _onexit_t func) {
|
|||||||
DEBUG_LOG("_register_onexit_function(%p, %p)\n", table, func);
|
DEBUG_LOG("_register_onexit_function(%p, %p)\n", table, func);
|
||||||
if (!table || !func)
|
if (!table || !func)
|
||||||
return -1;
|
return -1;
|
||||||
if (table->last == table->end) {
|
GUEST_PTR *first = reinterpret_cast<GUEST_PTR *>(fromGuestPtr(table->first));
|
||||||
size_t count = table->end - 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;
|
size_t newCount = count + 1;
|
||||||
if (newCount <= 0)
|
if (newCount <= 0)
|
||||||
return -1;
|
return -1;
|
||||||
_onexit_t *newTable =
|
GUEST_PTR *newTable = static_cast<GUEST_PTR *>(wibo::heap::guestRealloc(first, newCount * sizeof(GUEST_PTR)));
|
||||||
static_cast<_onexit_t *>(wibo::heap::guestRealloc(table->first, newCount * sizeof(_onexit_t)));
|
|
||||||
if (!newTable)
|
if (!newTable)
|
||||||
return -1;
|
return -1;
|
||||||
table->first = newTable;
|
table->first = toGuestPtr(newTable);
|
||||||
table->last = newTable + count;
|
last = newTable + count;
|
||||||
table->end = newTable + newCount;
|
table->end = toGuestPtr(newTable + newCount);
|
||||||
}
|
}
|
||||||
*table->last++ = func;
|
*last = toGuestPtr(reinterpret_cast<void *>(func));
|
||||||
|
table->last = toGuestPtr(last + 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,9 +351,12 @@ int CDECL _execute_onexit_table(_onexit_table_t *table) {
|
|||||||
DEBUG_LOG("_execute_onexit_table(%p)\n", table);
|
DEBUG_LOG("_execute_onexit_table(%p)\n", table);
|
||||||
if (!table)
|
if (!table)
|
||||||
return -1;
|
return -1;
|
||||||
for (auto it = table->first; it != table->last; ++it) {
|
GUEST_PTR *first = reinterpret_cast<GUEST_PTR *>(fromGuestPtr(table->first));
|
||||||
DEBUG_LOG("Calling onexit_table function %p\n", *it);
|
GUEST_PTR *last = reinterpret_cast<GUEST_PTR *>(fromGuestPtr(table->last));
|
||||||
call__onexit_t(*it);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -345,7 +408,7 @@ void *CDECL __acrt_iob_func(unsigned int index) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, _FILE *stream, const char *format, void *locale,
|
int CDECL_NO_CONV __stdio_common_vfprintf(ULONGLONG options, _FILE *stream, const char *format, void *locale,
|
||||||
va_list args) {
|
va_list args) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("__stdio_common_vfprintf(%llu, %p, %s, %p, %p)\n", options, stream, format, locale, args);
|
DEBUG_LOG("__stdio_common_vfprintf(%llu, %p, %s, %p, %p)\n", options, stream, format, locale, args);
|
||||||
@@ -355,8 +418,8 @@ int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, _FILE *str
|
|||||||
return vfprintf(hostFile, format, args);
|
return vfprintf(hostFile, format, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CDECL_NO_CONV __stdio_common_vsprintf(unsigned long long options, char *buffer, SIZE_T len, const char *format,
|
int CDECL_NO_CONV __stdio_common_vsprintf(ULONGLONG options, char *buffer, SIZE_T len, const char *format, void *locale,
|
||||||
void *locale, va_list args) {
|
va_list args) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("__stdio_common_vsprintf(%llu, %p, %zu, %s, %p, ...)\n", options, buffer, len, format, locale);
|
DEBUG_LOG("__stdio_common_vsprintf(%llu, %p, %zu, %s, %p, ...)\n", options, buffer, len, format, locale);
|
||||||
if (!buffer || !format)
|
if (!buffer || !format)
|
||||||
|
|||||||
30
dll/crt.h
30
dll/crt.h
@@ -23,9 +23,9 @@ typedef int(_CC_CDECL *sort_compare)(const void *, const void *);
|
|||||||
typedef int(_CC_CDECL *_onexit_t)();
|
typedef int(_CC_CDECL *_onexit_t)();
|
||||||
|
|
||||||
struct _onexit_table_t {
|
struct _onexit_table_t {
|
||||||
_onexit_t *first;
|
GUEST_PTR first;
|
||||||
_onexit_t *last;
|
GUEST_PTR last;
|
||||||
_onexit_t *end;
|
GUEST_PTR end;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace crt {
|
namespace crt {
|
||||||
@@ -33,23 +33,23 @@ namespace crt {
|
|||||||
extern int _commode;
|
extern int _commode;
|
||||||
extern int _fmode;
|
extern int _fmode;
|
||||||
|
|
||||||
void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end);
|
void CDECL _initterm(GUEST_PTR *ppfn, GUEST_PTR *end);
|
||||||
int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end);
|
int CDECL _initterm_e(GUEST_PTR *ppfn, GUEST_PTR *end);
|
||||||
void CDECL _set_app_type(_crt_app_type type);
|
void CDECL _set_app_type(_crt_app_type type);
|
||||||
int CDECL _set_fmode(int mode);
|
int CDECL _set_fmode(int mode);
|
||||||
int *CDECL __p__commode();
|
GUEST_PTR CDECL __p__commode();
|
||||||
int *CDECL __p__fmode();
|
GUEST_PTR CDECL __p__fmode();
|
||||||
int CDECL _crt_atexit(void (*func)());
|
int CDECL _crt_atexit(_PVFV func);
|
||||||
int CDECL _configure_narrow_argv(_crt_argv_mode mode);
|
int CDECL _configure_narrow_argv(_crt_argv_mode mode);
|
||||||
_invalid_parameter_handler CDECL _set_invalid_parameter_handler(_invalid_parameter_handler newHandler);
|
_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 _controlfp_s(unsigned int *currentControl, unsigned int newControl, unsigned int mask);
|
||||||
int CDECL _configthreadlocale(int per_thread_locale_type);
|
int CDECL _configthreadlocale(int per_thread_locale_type);
|
||||||
int CDECL _initialize_narrow_environment();
|
int CDECL _initialize_narrow_environment();
|
||||||
int CDECL _set_new_mode(int newhandlermode);
|
int CDECL _set_new_mode(int newhandlermode);
|
||||||
char **CDECL _get_initial_narrow_environment();
|
GUEST_PTR CDECL _get_initial_narrow_environment();
|
||||||
char ***CDECL __p__environ();
|
GUEST_PTR CDECL __p__environ();
|
||||||
char ***CDECL __p___argv();
|
GUEST_PTR CDECL __p___argv();
|
||||||
int *CDECL __p___argc();
|
GUEST_PTR CDECL __p___argc();
|
||||||
SIZE_T CDECL strlen(const char *str);
|
SIZE_T CDECL strlen(const char *str);
|
||||||
int CDECL strcmp(const char *lhs, const char *rhs);
|
int CDECL strcmp(const char *lhs, const char *rhs);
|
||||||
int CDECL strncmp(const char *lhs, const char *rhs, SIZE_T count);
|
int CDECL strncmp(const char *lhs, const char *rhs, SIZE_T count);
|
||||||
@@ -74,10 +74,12 @@ void CDECL _exit(int status);
|
|||||||
void CDECL abort();
|
void CDECL abort();
|
||||||
signal_handler CDECL signal(int signum, signal_handler handler);
|
signal_handler CDECL signal(int signum, signal_handler handler);
|
||||||
void *CDECL __acrt_iob_func(unsigned int index);
|
void *CDECL __acrt_iob_func(unsigned int index);
|
||||||
int CDECL_NO_CONV __stdio_common_vfprintf(unsigned long long options, _FILE *stream, const char *format, void *locale,
|
#ifndef __x86_64__ // TODO
|
||||||
|
int CDECL_NO_CONV __stdio_common_vfprintf(ULONGLONG options, _FILE *stream, const char *format, void *locale,
|
||||||
va_list args);
|
va_list args);
|
||||||
int CDECL_NO_CONV __stdio_common_vsprintf(unsigned long long options, char *buffer, SIZE_T len, const char *format,
|
int CDECL_NO_CONV __stdio_common_vsprintf(ULONGLONG options, char *buffer, SIZE_T len, const char *format,
|
||||||
void *locale, va_list args);
|
void *locale, va_list args);
|
||||||
|
#endif
|
||||||
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare);
|
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare);
|
||||||
int CDECL puts(const char *str);
|
int CDECL puts(const char *str);
|
||||||
|
|
||||||
|
|||||||
@@ -7,14 +7,14 @@ constexpr DWORD EXCEPTION_MAXIMUM_PARAMETERS = 15;
|
|||||||
struct EXCEPTION_RECORD {
|
struct EXCEPTION_RECORD {
|
||||||
DWORD ExceptionCode;
|
DWORD ExceptionCode;
|
||||||
DWORD ExceptionFlags;
|
DWORD ExceptionFlags;
|
||||||
EXCEPTION_RECORD *ExceptionRecord;
|
GUEST_PTR ExceptionRecord;
|
||||||
PVOID ExceptionAddress;
|
GUEST_PTR ExceptionAddress;
|
||||||
DWORD NumberParameters;
|
DWORD NumberParameters;
|
||||||
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
|
ULONG_PTR ExceptionInformation[EXCEPTION_MAXIMUM_PARAMETERS];
|
||||||
};
|
};
|
||||||
|
|
||||||
using PEXCEPTION_RECORD = EXCEPTION_RECORD *;
|
using PEXCEPTION_RECORD = GUEST_PTR;
|
||||||
using PCONTEXT = void *;
|
using PCONTEXT = GUEST_PTR;
|
||||||
|
|
||||||
struct EXCEPTION_POINTERS {
|
struct EXCEPTION_POINTERS {
|
||||||
PEXCEPTION_RECORD ExceptionRecord;
|
PEXCEPTION_RECORD ExceptionRecord;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@
|
|||||||
#include "overlapped_util.h"
|
#include "overlapped_util.h"
|
||||||
#include "strutil.h"
|
#include "strutil.h"
|
||||||
#include "timeutil.h"
|
#include "timeutil.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cctype>
|
#include <cctype>
|
||||||
@@ -146,24 +147,24 @@ struct FindSearchHandle {
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::mutex g_findHandleMutex;
|
std::mutex g_findHandleMutex;
|
||||||
std::unordered_map<FindSearchHandle *, std::unique_ptr<FindSearchHandle>> g_findHandles;
|
HANDLE g_nextFindHandle = 1;
|
||||||
|
std::unordered_map<HANDLE, std::unique_ptr<FindSearchHandle>> g_findHandles;
|
||||||
|
|
||||||
HANDLE registerFindHandle(std::unique_ptr<FindSearchHandle> handle) {
|
HANDLE registerFindHandle(std::unique_ptr<FindSearchHandle> handle) {
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
return INVALID_HANDLE_VALUE;
|
return INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
FindSearchHandle *raw = handle.get();
|
|
||||||
std::lock_guard lk(g_findHandleMutex);
|
std::lock_guard lk(g_findHandleMutex);
|
||||||
|
HANDLE raw = g_nextFindHandle++;
|
||||||
g_findHandles.emplace(raw, std::move(handle));
|
g_findHandles.emplace(raw, std::move(handle));
|
||||||
return reinterpret_cast<HANDLE>(raw);
|
return raw;
|
||||||
}
|
}
|
||||||
|
|
||||||
FindSearchHandle *lookupFindHandleLocked(HANDLE handle) {
|
FindSearchHandle *lookupFindHandleLocked(HANDLE handle) {
|
||||||
if (handle == nullptr) {
|
if (handle == NO_HANDLE) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
auto *raw = reinterpret_cast<FindSearchHandle *>(handle);
|
auto it = g_findHandles.find(handle);
|
||||||
auto it = g_findHandles.find(raw);
|
|
||||||
if (it == g_findHandles.end()) {
|
if (it == g_findHandles.end()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -172,8 +173,7 @@ FindSearchHandle *lookupFindHandleLocked(HANDLE handle) {
|
|||||||
|
|
||||||
std::unique_ptr<FindSearchHandle> detachFindHandle(HANDLE handle) {
|
std::unique_ptr<FindSearchHandle> detachFindHandle(HANDLE handle) {
|
||||||
std::lock_guard lk(g_findHandleMutex);
|
std::lock_guard lk(g_findHandleMutex);
|
||||||
auto *raw = reinterpret_cast<FindSearchHandle *>(handle);
|
auto it = g_findHandles.find(handle);
|
||||||
auto it = g_findHandles.find(raw);
|
|
||||||
if (it == g_findHandles.end()) {
|
if (it == g_findHandles.end()) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -1185,7 +1185,7 @@ DWORD WINAPI SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistance
|
|||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("SetFilePointer(%p, %ld, %p, %u)\n", hFile, static_cast<long>(lDistanceToMove), lpDistanceToMoveHigh,
|
DEBUG_LOG("SetFilePointer(%p, %ld, %p, %u)\n", hFile, static_cast<long>(lDistanceToMove), lpDistanceToMoveHigh,
|
||||||
dwMoveMethod);
|
dwMoveMethod);
|
||||||
if (hFile == nullptr) {
|
if (hFile == NO_HANDLE) {
|
||||||
setLastError(ERROR_INVALID_HANDLE);
|
setLastError(ERROR_INVALID_HANDLE);
|
||||||
return INVALID_SET_FILE_POINTER;
|
return INVALID_SET_FILE_POINTER;
|
||||||
}
|
}
|
||||||
@@ -1224,7 +1224,8 @@ DWORD WINAPI SetFilePointer(HANDLE hFile, LONG lDistanceToMove, PLONG lpDistance
|
|||||||
BOOL WINAPI SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer,
|
BOOL WINAPI SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistanceToMove, PLARGE_INTEGER lpNewFilePointer,
|
||||||
DWORD dwMoveMethod) {
|
DWORD dwMoveMethod) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
if (hFile == nullptr) {
|
DEBUG_LOG("SetFilePointerEx(%p, %lld, %p, %u)\n", hFile, liDistanceToMove.QuadPart, lpNewFilePointer, dwMoveMethod);
|
||||||
|
if (hFile == NO_HANDLE) {
|
||||||
setLastError(ERROR_INVALID_HANDLE);
|
setLastError(ERROR_INVALID_HANDLE);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -1537,12 +1538,12 @@ DWORD WINAPI GetFileType(HANDLE hFile) {
|
|||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR *lpFilePart) {
|
DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, GUEST_PTR *lpFilePart) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("GetFullPathNameA(%s, %u)\n", lpFileName ? lpFileName : "(null)", nBufferLength);
|
DEBUG_LOG("GetFullPathNameA(%s, %u)\n", lpFileName ? lpFileName : "(null)", nBufferLength);
|
||||||
|
|
||||||
if (lpFilePart) {
|
if (lpFilePart) {
|
||||||
*lpFilePart = nullptr;
|
*lpFilePart = GUEST_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lpFileName) {
|
if (!lpFileName) {
|
||||||
@@ -1580,21 +1581,21 @@ DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBu
|
|||||||
|
|
||||||
if (lpFilePart) {
|
if (lpFilePart) {
|
||||||
if (info.filePartOffset != std::string::npos && info.filePartOffset < pathLen) {
|
if (info.filePartOffset != std::string::npos && info.filePartOffset < pathLen) {
|
||||||
*lpFilePart = lpBuffer + info.filePartOffset;
|
*lpFilePart = toGuestPtr(lpBuffer + info.filePartOffset);
|
||||||
} else {
|
} else {
|
||||||
*lpFilePart = nullptr;
|
*lpFilePart = GUEST_NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return static_cast<DWORD>(pathLen);
|
return static_cast<DWORD>(pathLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart) {
|
DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, GUEST_PTR *lpFilePart) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("GetFullPathNameW(%p, %u)\n", lpFileName, nBufferLength);
|
DEBUG_LOG("GetFullPathNameW(%p, %u)\n", lpFileName, nBufferLength);
|
||||||
|
|
||||||
if (lpFilePart) {
|
if (lpFilePart) {
|
||||||
*lpFilePart = nullptr;
|
*lpFilePart = GUEST_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!lpFileName) {
|
if (!lpFileName) {
|
||||||
@@ -1633,9 +1634,9 @@ DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lp
|
|||||||
|
|
||||||
if (lpFilePart) {
|
if (lpFilePart) {
|
||||||
if (info.filePartOffset != std::string::npos && info.filePartOffset < info.path.size()) {
|
if (info.filePartOffset != std::string::npos && info.filePartOffset < info.path.size()) {
|
||||||
*lpFilePart = lpBuffer + info.filePartOffset;
|
*lpFilePart = toGuestPtr(lpBuffer + info.filePartOffset);
|
||||||
} else {
|
} else {
|
||||||
*lpFilePart = nullptr;
|
*lpFilePart = GUEST_NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1883,7 +1884,7 @@ BOOL WINAPI FindNextFileW(HANDLE hFindFile, LPWIN32_FIND_DATAW lpFindFileData) {
|
|||||||
BOOL WINAPI FindClose(HANDLE hFindFile) {
|
BOOL WINAPI FindClose(HANDLE hFindFile) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("FindClose(%p)\n", hFindFile);
|
DEBUG_LOG("FindClose(%p)\n", hFindFile);
|
||||||
if (hFindFile == nullptr) {
|
if (hFindFile == NO_HANDLE) {
|
||||||
DEBUG_LOG(" -> ERROR_INVALID_HANDLE\n");
|
DEBUG_LOG(" -> ERROR_INVALID_HANDLE\n");
|
||||||
setLastError(ERROR_INVALID_HANDLE);
|
setLastError(ERROR_INVALID_HANDLE);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|||||||
@@ -56,8 +56,8 @@ constexpr DWORD INVALID_FILE_SIZE = 0xFFFFFFFF;
|
|||||||
|
|
||||||
namespace kernel32 {
|
namespace kernel32 {
|
||||||
|
|
||||||
DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, LPSTR *lpFilePart);
|
DWORD WINAPI GetFullPathNameA(LPCSTR lpFileName, DWORD nBufferLength, LPSTR lpBuffer, GUEST_PTR *lpFilePart);
|
||||||
DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR *lpFilePart);
|
DWORD WINAPI GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, GUEST_PTR *lpFilePart);
|
||||||
DWORD WINAPI GetShortPathNameA(LPCSTR lpszLongPath, LPSTR lpszShortPath, DWORD cchBuffer);
|
DWORD WINAPI GetShortPathNameA(LPCSTR lpszLongPath, LPSTR lpszShortPath, DWORD cchBuffer);
|
||||||
DWORD WINAPI GetShortPathNameW(LPCWSTR lpszLongPath, LPWSTR lpszShortPath, DWORD cchBuffer);
|
DWORD WINAPI GetShortPathNameW(LPCWSTR lpszLongPath, LPWSTR lpszShortPath, DWORD cchBuffer);
|
||||||
UINT WINAPI GetTempFileNameA(LPCSTR lpPathName, LPCSTR lpPrefixString, UINT uUnique, LPSTR lpTempFileName);
|
UINT WINAPI GetTempFileNameA(LPCSTR lpPathName, LPCSTR lpPrefixString, UINT uUnique, LPSTR lpTempFileName);
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
namespace kernel32 {
|
namespace kernel32 {
|
||||||
|
|
||||||
BOOL WINAPI DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle,
|
BOOL WINAPI DuplicateHandle(HANDLE hSourceProcessHandle, HANDLE hSourceHandle, HANDLE hTargetProcessHandle,
|
||||||
LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions) {
|
LPHANDLE lpTargetHandle, DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwOptions) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("DuplicateHandle(%p, %p, %p, %p, %x, %d, %x)\n", hSourceProcessHandle, hSourceHandle,
|
DEBUG_LOG("DuplicateHandle(%p, %p, %p, %p, %x, %d, %x)\n", hSourceProcessHandle, hSourceHandle,
|
||||||
hTargetProcessHandle, lpTargetHandle, dwDesiredAccess, bInheritHandle, dwOptions);
|
hTargetProcessHandle, lpTargetHandle, dwDesiredAccess, bInheritHandle, dwOptions);
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ using kernel32::HeapObject;
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
std::once_flag g_processHeapInitFlag;
|
std::once_flag g_processHeapInitFlag;
|
||||||
HANDLE g_processHeapHandle = nullptr;
|
HANDLE g_processHeapHandle = NO_HANDLE;
|
||||||
HeapObject *g_processHeapRecord = nullptr;
|
HeapObject *g_processHeapRecord = nullptr;
|
||||||
|
|
||||||
void ensureProcessHeapInitialized() {
|
void ensureProcessHeapInitialized() {
|
||||||
@@ -71,7 +71,7 @@ HeapObject::~HeapObject() {
|
|||||||
heap = nullptr;
|
heap = nullptr;
|
||||||
}
|
}
|
||||||
if (isProcessHeap) {
|
if (isProcessHeap) {
|
||||||
g_processHeapHandle = nullptr;
|
g_processHeapHandle = NO_HANDLE;
|
||||||
g_processHeapRecord = nullptr;
|
g_processHeapRecord = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,13 +83,13 @@ HANDLE WINAPI HeapCreate(DWORD flOptions, SIZE_T dwInitialSize, SIZE_T dwMaximum
|
|||||||
DEBUG_LOG("HeapCreate(%u, %zu, %zu)\n", flOptions, dwInitialSize, dwMaximumSize);
|
DEBUG_LOG("HeapCreate(%u, %zu, %zu)\n", flOptions, dwInitialSize, dwMaximumSize);
|
||||||
if (dwMaximumSize != 0 && dwInitialSize > dwMaximumSize) {
|
if (dwMaximumSize != 0 && dwInitialSize > dwMaximumSize) {
|
||||||
setLastError(ERROR_INVALID_PARAMETER);
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
mi_heap_t *heap = wibo::heap::createGuestHeap();
|
mi_heap_t *heap = wibo::heap::createGuestHeap();
|
||||||
if (!heap) {
|
if (!heap) {
|
||||||
setLastError(ERROR_NOT_ENOUGH_MEMORY);
|
setLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto record = make_pin<HeapObject>(heap);
|
auto record = make_pin<HeapObject>(heap);
|
||||||
|
|||||||
@@ -5,13 +5,13 @@
|
|||||||
namespace kernel32 {
|
namespace kernel32 {
|
||||||
|
|
||||||
struct SLIST_ENTRY {
|
struct SLIST_ENTRY {
|
||||||
SLIST_ENTRY *Next;
|
GUEST_PTR Next;
|
||||||
};
|
};
|
||||||
|
|
||||||
using PSLIST_ENTRY = SLIST_ENTRY *;
|
using PSLIST_ENTRY = SLIST_ENTRY *;
|
||||||
|
|
||||||
struct SLIST_HEADER {
|
struct SLIST_HEADER {
|
||||||
SLIST_ENTRY *Head;
|
GUEST_PTR Head;
|
||||||
unsigned short Depth;
|
unsigned short Depth;
|
||||||
unsigned short Sequence;
|
unsigned short Sequence;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -160,17 +160,15 @@ struct HeapObject : public ObjectBase {
|
|||||||
[[nodiscard]] inline bool canAccess() const { return isProcessHeap || (isOwner() && heap != nullptr); }
|
[[nodiscard]] inline bool canAccess() const { return isProcessHeap || (isOwner() && heap != nullptr); }
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr uintptr_t kPseudoCurrentProcessHandleValue = static_cast<uintptr_t>(-1);
|
inline constexpr HANDLE kPseudoCurrentProcessHandleValue = static_cast<HANDLE>(-1);
|
||||||
inline constexpr uintptr_t kPseudoCurrentThreadHandleValue = static_cast<uintptr_t>(-2);
|
inline constexpr HANDLE kPseudoCurrentThreadHandleValue = static_cast<HANDLE>(-2);
|
||||||
|
|
||||||
inline bool isPseudoCurrentProcessHandle(HANDLE h) {
|
inline bool isPseudoCurrentProcessHandle(HANDLE h) {
|
||||||
uintptr_t rawHandle = reinterpret_cast<uintptr_t>(h);
|
return h == kPseudoCurrentProcessHandleValue;
|
||||||
return rawHandle == kPseudoCurrentProcessHandleValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isPseudoCurrentThreadHandle(HANDLE h) {
|
inline bool isPseudoCurrentThreadHandle(HANDLE h) {
|
||||||
uintptr_t rawHandle = reinterpret_cast<uintptr_t>(h);
|
return h == kPseudoCurrentThreadHandleValue;
|
||||||
return rawHandle == kPseudoCurrentThreadHandleValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void tryMarkExecutable(void *mem);
|
void tryMarkExecutable(void *mem);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "modules.h"
|
#include "modules.h"
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
#include "strutil.h"
|
#include "strutil.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@@ -20,13 +21,13 @@ HRSRC findResourceInternal(HMODULE hModule, const wibo::ResourceIdentifier &type
|
|||||||
auto *exe = wibo::executableFromModule(hModule);
|
auto *exe = wibo::executableFromModule(hModule);
|
||||||
if (!exe) {
|
if (!exe) {
|
||||||
kernel32::setLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
|
kernel32::setLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
wibo::ResourceLocation loc;
|
wibo::ResourceLocation loc;
|
||||||
if (!exe->findResource(type, name, language, loc)) {
|
if (!exe->findResource(type, name, language, loc)) {
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
return reinterpret_cast<HRSRC>(const_cast<void *>(loc.dataEntry));
|
return toGuestPtr(loc.dataEntry);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -58,7 +59,7 @@ HMODULE WINAPI GetModuleHandleA(LPCSTR lpModuleName) {
|
|||||||
const auto *module = wibo::findLoadedModule(lpModuleName);
|
const auto *module = wibo::findLoadedModule(lpModuleName);
|
||||||
if (!module) {
|
if (!module) {
|
||||||
setLastError(ERROR_MOD_NOT_FOUND);
|
setLastError(ERROR_MOD_NOT_FOUND);
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
return module->handle;
|
return module->handle;
|
||||||
}
|
}
|
||||||
@@ -111,7 +112,7 @@ DWORD WINAPI GetModuleFileNameA(HMODULE hModule, LPSTR lpFilename, DWORD nSize)
|
|||||||
|
|
||||||
DWORD WINAPI GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, DWORD nSize) {
|
DWORD WINAPI GetModuleFileNameW(HMODULE hModule, LPWSTR lpFilename, DWORD nSize) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("GetModuleFileNameW(%p, %s, %u)\n", hModule, wideStringToString(lpFilename).c_str(), nSize);
|
DEBUG_LOG("GetModuleFileNameW(%p, %p, %u)\n", hModule, lpFilename, nSize);
|
||||||
if (!lpFilename) {
|
if (!lpFilename) {
|
||||||
setLastError(ERROR_INVALID_PARAMETER);
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -187,25 +188,25 @@ HGLOBAL WINAPI LoadResource(HMODULE hModule, HRSRC hResInfo) {
|
|||||||
DEBUG_LOG("LoadResource %p %p\n", hModule, hResInfo);
|
DEBUG_LOG("LoadResource %p %p\n", hModule, hResInfo);
|
||||||
if (!hResInfo) {
|
if (!hResInfo) {
|
||||||
setLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
|
setLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
|
||||||
return nullptr;
|
return GUEST_NULL;
|
||||||
}
|
}
|
||||||
auto *exe = wibo::executableFromModule(hModule);
|
auto *exe = wibo::executableFromModule(hModule);
|
||||||
if (!exe || !exe->rsrcBase) {
|
if (!exe || !exe->rsrcBase) {
|
||||||
setLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
|
setLastError(ERROR_RESOURCE_DATA_NOT_FOUND);
|
||||||
return nullptr;
|
return GUEST_NULL;
|
||||||
}
|
}
|
||||||
const auto *entry = reinterpret_cast<const wibo::ImageResourceDataEntry *>(hResInfo);
|
const auto *entry = reinterpret_cast<const wibo::ImageResourceDataEntry *>(hResInfo);
|
||||||
if (!wibo::resourceEntryBelongsToExecutable(*exe, entry)) {
|
if (!wibo::resourceEntryBelongsToExecutable(*exe, entry)) {
|
||||||
setLastError(ERROR_INVALID_PARAMETER);
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return nullptr;
|
return GUEST_NULL;
|
||||||
}
|
}
|
||||||
return const_cast<void *>(exe->fromRVA<const void>(entry->offsetToData));
|
return toGuestPtr(exe->fromRVA<const void>(entry->offsetToData));
|
||||||
}
|
}
|
||||||
|
|
||||||
LPVOID WINAPI LockResource(HGLOBAL hResData) {
|
LPVOID WINAPI LockResource(HGLOBAL hResData) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("LockResource(%p)\n", hResData);
|
DEBUG_LOG("LockResource(%p)\n", hResData);
|
||||||
return hResData;
|
return (LPVOID)hResData;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD WINAPI SizeofResource(HMODULE hModule, HRSRC hResInfo) {
|
DWORD WINAPI SizeofResource(HMODULE hModule, HRSRC hResInfo) {
|
||||||
@@ -234,7 +235,7 @@ HMODULE WINAPI LoadLibraryA(LPCSTR lpLibFileName) {
|
|||||||
const auto *info = wibo::loadModule(lpLibFileName);
|
const auto *info = wibo::loadModule(lpLibFileName);
|
||||||
if (!info) {
|
if (!info) {
|
||||||
// lastError is set by loadModule
|
// lastError is set by loadModule
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
return info->handle;
|
return info->handle;
|
||||||
}
|
}
|
||||||
@@ -242,7 +243,7 @@ HMODULE WINAPI LoadLibraryA(LPCSTR lpLibFileName) {
|
|||||||
HMODULE WINAPI LoadLibraryW(LPCWSTR lpLibFileName) {
|
HMODULE WINAPI LoadLibraryW(LPCWSTR lpLibFileName) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
if (!lpLibFileName) {
|
if (!lpLibFileName) {
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
auto filename = wideStringToString(lpLibFileName);
|
auto filename = wideStringToString(lpLibFileName);
|
||||||
DEBUG_LOG("LoadLibraryW(%s)\n", filename.c_str());
|
DEBUG_LOG("LoadLibraryW(%s)\n", filename.c_str());
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "strutil.h"
|
#include "strutil.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -161,8 +162,8 @@ bool mappedViewRegionForAddress(uintptr_t request, uintptr_t pageBase, MEMORY_BA
|
|||||||
}
|
}
|
||||||
uintptr_t blockStart = viewStart;
|
uintptr_t blockStart = viewStart;
|
||||||
uintptr_t blockEnd = alignUp(viewEnd, pageSize);
|
uintptr_t blockEnd = alignUp(viewEnd, pageSize);
|
||||||
info.BaseAddress = reinterpret_cast<void *>(blockStart);
|
info.BaseAddress = toGuestPtr(reinterpret_cast<void *>(blockStart));
|
||||||
info.AllocationBase = reinterpret_cast<void *>(view.viewBase);
|
info.AllocationBase = toGuestPtr(reinterpret_cast<void *>(view.viewBase));
|
||||||
info.AllocationProtect = view.allocationProtect;
|
info.AllocationProtect = view.allocationProtect;
|
||||||
info.RegionSize = blockEnd > blockStart ? blockEnd - blockStart : 0;
|
info.RegionSize = blockEnd > blockStart ? blockEnd - blockStart : 0;
|
||||||
info.State = MEM_COMMIT;
|
info.State = MEM_COMMIT;
|
||||||
@@ -189,7 +190,7 @@ HANDLE WINAPI CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappi
|
|||||||
if (flProtect != PAGE_READONLY && flProtect != PAGE_READWRITE && flProtect != PAGE_WRITECOPY) {
|
if (flProtect != PAGE_READONLY && flProtect != PAGE_READWRITE && flProtect != PAGE_WRITECOPY) {
|
||||||
DEBUG_LOG("CreateFileMappingA: unsupported protection 0x%x\n", flProtect);
|
DEBUG_LOG("CreateFileMappingA: unsupported protection 0x%x\n", flProtect);
|
||||||
setLastError(ERROR_INVALID_PARAMETER);
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto mapping = make_pin<MappingObject>();
|
auto mapping = make_pin<MappingObject>();
|
||||||
@@ -200,25 +201,25 @@ HANDLE WINAPI CreateFileMappingA(HANDLE hFile, LPSECURITY_ATTRIBUTES lpFileMappi
|
|||||||
mapping->fd = -1;
|
mapping->fd = -1;
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
setLastError(ERROR_INVALID_PARAMETER);
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
mapping->maxSize = size;
|
mapping->maxSize = size;
|
||||||
} else {
|
} else {
|
||||||
auto file = wibo::handles().getAs<FileObject>(hFile);
|
auto file = wibo::handles().getAs<FileObject>(hFile);
|
||||||
if (!file || !file->valid()) {
|
if (!file || !file->valid()) {
|
||||||
setLastError(ERROR_INVALID_HANDLE);
|
setLastError(ERROR_INVALID_HANDLE);
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
int dupFd = fcntl(file->fd, F_DUPFD_CLOEXEC, 0);
|
int dupFd = fcntl(file->fd, F_DUPFD_CLOEXEC, 0);
|
||||||
if (dupFd == -1) {
|
if (dupFd == -1) {
|
||||||
setLastErrorFromErrno();
|
setLastErrorFromErrno();
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
mapping->fd = dupFd;
|
mapping->fd = dupFd;
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
off_t fileSize = lseek(dupFd, 0, SEEK_END);
|
off_t fileSize = lseek(dupFd, 0, SEEK_END);
|
||||||
if (fileSize < 0) {
|
if (fileSize < 0) {
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
size = static_cast<uint64_t>(fileSize);
|
size = static_cast<uint64_t>(fileSize);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
struct SECURITY_ATTRIBUTES {
|
struct SECURITY_ATTRIBUTES {
|
||||||
DWORD nLength;
|
DWORD nLength;
|
||||||
LPVOID lpSecurityDescriptor;
|
GUEST_PTR lpSecurityDescriptor;
|
||||||
BOOL bInheritHandle;
|
BOOL bInheritHandle;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ typedef struct _OVERLAPPED {
|
|||||||
DWORD Offset;
|
DWORD Offset;
|
||||||
DWORD OffsetHigh;
|
DWORD OffsetHigh;
|
||||||
};
|
};
|
||||||
PVOID Pointer;
|
GUEST_PTR Pointer;
|
||||||
};
|
};
|
||||||
HANDLE hEvent;
|
HANDLE hEvent;
|
||||||
} OVERLAPPED, *LPOVERLAPPED;
|
} OVERLAPPED, *LPOVERLAPPED;
|
||||||
|
|||||||
@@ -355,8 +355,8 @@ BOOL WINAPI CreatePipe(PHANDLE hReadPipe, PHANDLE hWritePipe, LPSECURITY_ATTRIBU
|
|||||||
setLastError(ERROR_INVALID_PARAMETER);
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
*hReadPipe = nullptr;
|
*hReadPipe = NO_HANDLE;
|
||||||
*hWritePipe = nullptr;
|
*hWritePipe = NO_HANDLE;
|
||||||
|
|
||||||
int pipeFds[2];
|
int pipeFds[2];
|
||||||
if (pipe(pipeFds) != 0) {
|
if (pipe(pipeFds) != 0) {
|
||||||
|
|||||||
@@ -1,17 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "errors.h"
|
|
||||||
#include "handles.h"
|
#include "handles.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "minwinbase.h"
|
#include "minwinbase.h"
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
|
|
||||||
namespace kernel32::detail {
|
namespace kernel32::detail {
|
||||||
|
|
||||||
inline HANDLE normalizedOverlappedEventHandle(const OVERLAPPED *ov) {
|
inline HANDLE normalizedOverlappedEventHandle(const OVERLAPPED *ov) {
|
||||||
if (!ov || (reinterpret_cast<uintptr_t>(ov->hEvent) & 1U) != 0) {
|
if (!ov || (ov->hEvent & 1U) != 0) {
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
return ov->hEvent;
|
return ov->hEvent;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "strutil.h"
|
#include "strutil.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -16,6 +17,9 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
GUEST_PTR g_commandLineA = GUEST_NULL;
|
||||||
|
GUEST_PTR g_commandLineW = GUEST_NULL;
|
||||||
|
|
||||||
std::string convertEnvValueForWindows(const std::string &name, const char *rawValue) {
|
std::string convertEnvValueForWindows(const std::string &name, const char *rawValue) {
|
||||||
if (!rawValue) {
|
if (!rawValue) {
|
||||||
return {};
|
return {};
|
||||||
@@ -42,16 +46,26 @@ std::string convertEnvValueToHost(const std::string &name, const char *rawValue)
|
|||||||
|
|
||||||
namespace kernel32 {
|
namespace kernel32 {
|
||||||
|
|
||||||
LPSTR WINAPI GetCommandLineA() {
|
GUEST_PTR WINAPI GetCommandLineA() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("GetCommandLineA() -> %s\n", wibo::commandLine.c_str());
|
DEBUG_LOG("GetCommandLineA() -> %s\n", wibo::commandLine.c_str());
|
||||||
return const_cast<LPSTR>(wibo::commandLine.c_str());
|
if (g_commandLineA == GUEST_NULL) {
|
||||||
|
void *tmp = wibo::heap::guestCalloc(1, wibo::commandLine.size() + 1);
|
||||||
|
memcpy(tmp, wibo::commandLine.c_str(), wibo::commandLine.size());
|
||||||
|
g_commandLineA = toGuestPtr(tmp);
|
||||||
|
}
|
||||||
|
return g_commandLineA;
|
||||||
}
|
}
|
||||||
|
|
||||||
LPWSTR WINAPI GetCommandLineW() {
|
GUEST_PTR WINAPI GetCommandLineW() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("GetCommandLineW() -> %s\n", wideStringToString(wibo::commandLineW.data()).c_str());
|
DEBUG_LOG("GetCommandLineW() -> %s\n", wideStringToString(wibo::commandLineW.data()).c_str());
|
||||||
return wibo::commandLineW.data();
|
if (g_commandLineW == GUEST_NULL) {
|
||||||
|
void *tmp = wibo::heap::guestCalloc(1, wibo::commandLineW.size() * sizeof(WCHAR) + sizeof(WCHAR));
|
||||||
|
memcpy(tmp, wibo::commandLineW.data(), wibo::commandLineW.size() * sizeof(WCHAR));
|
||||||
|
g_commandLineW = toGuestPtr(tmp);
|
||||||
|
}
|
||||||
|
return g_commandLineW;
|
||||||
}
|
}
|
||||||
|
|
||||||
HANDLE WINAPI GetStdHandle(DWORD nStdHandle) {
|
HANDLE WINAPI GetStdHandle(DWORD nStdHandle) {
|
||||||
@@ -66,7 +80,11 @@ BOOL WINAPI SetStdHandle(DWORD nStdHandle, HANDLE hHandle) {
|
|||||||
return files::setStdHandle(nStdHandle, hHandle);
|
return files::setStdHandle(nStdHandle, hHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
LPCH WINAPI GetEnvironmentStrings() {
|
GUEST_PTR WINAPI GetEnvironmentStrings() {
|
||||||
|
return GetEnvironmentStringsA();
|
||||||
|
}
|
||||||
|
|
||||||
|
GUEST_PTR WINAPI GetEnvironmentStringsA() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("GetEnvironmentStrings()\n");
|
DEBUG_LOG("GetEnvironmentStrings()\n");
|
||||||
|
|
||||||
@@ -82,7 +100,7 @@ LPCH WINAPI GetEnvironmentStrings() {
|
|||||||
char *buffer = static_cast<char *>(wibo::heap::guestMalloc(bufSize));
|
char *buffer = static_cast<char *>(wibo::heap::guestMalloc(bufSize));
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
setLastError(ERROR_NOT_ENOUGH_MEMORY);
|
setLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
return nullptr;
|
return GUEST_NULL;
|
||||||
}
|
}
|
||||||
char *ptr = buffer;
|
char *ptr = buffer;
|
||||||
work = environ;
|
work = environ;
|
||||||
@@ -96,10 +114,10 @@ LPCH WINAPI GetEnvironmentStrings() {
|
|||||||
}
|
}
|
||||||
*ptr = 0;
|
*ptr = 0;
|
||||||
|
|
||||||
return buffer;
|
return toGuestPtr(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
LPWCH WINAPI GetEnvironmentStringsW() {
|
GUEST_PTR WINAPI GetEnvironmentStringsW() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("GetEnvironmentStringsW()\n");
|
DEBUG_LOG("GetEnvironmentStringsW()\n");
|
||||||
|
|
||||||
@@ -115,7 +133,7 @@ LPWCH WINAPI GetEnvironmentStringsW() {
|
|||||||
uint16_t *buffer = static_cast<uint16_t *>(wibo::heap::guestMalloc(bufSizeW * sizeof(uint16_t)));
|
uint16_t *buffer = static_cast<uint16_t *>(wibo::heap::guestMalloc(bufSizeW * sizeof(uint16_t)));
|
||||||
if (!buffer) {
|
if (!buffer) {
|
||||||
setLastError(ERROR_NOT_ENOUGH_MEMORY);
|
setLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
return nullptr;
|
return GUEST_NULL;
|
||||||
}
|
}
|
||||||
uint16_t *ptr = buffer;
|
uint16_t *ptr = buffer;
|
||||||
work = environ;
|
work = environ;
|
||||||
@@ -131,7 +149,7 @@ LPWCH WINAPI GetEnvironmentStringsW() {
|
|||||||
}
|
}
|
||||||
*ptr = 0;
|
*ptr = 0;
|
||||||
|
|
||||||
return buffer;
|
return toGuestPtr(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI FreeEnvironmentStringsA(LPCH penv) {
|
BOOL WINAPI FreeEnvironmentStringsA(LPCH penv) {
|
||||||
|
|||||||
@@ -4,12 +4,13 @@
|
|||||||
|
|
||||||
namespace kernel32 {
|
namespace kernel32 {
|
||||||
|
|
||||||
LPSTR WINAPI GetCommandLineA();
|
GUEST_PTR WINAPI GetCommandLineA();
|
||||||
LPWSTR WINAPI GetCommandLineW();
|
GUEST_PTR WINAPI GetCommandLineW();
|
||||||
HANDLE WINAPI GetStdHandle(DWORD nStdHandle);
|
HANDLE WINAPI GetStdHandle(DWORD nStdHandle);
|
||||||
BOOL WINAPI SetStdHandle(DWORD nStdHandle, HANDLE hHandle);
|
BOOL WINAPI SetStdHandle(DWORD nStdHandle, HANDLE hHandle);
|
||||||
LPCH WINAPI GetEnvironmentStrings();
|
GUEST_PTR WINAPI GetEnvironmentStrings();
|
||||||
LPWCH WINAPI GetEnvironmentStringsW();
|
GUEST_PTR WINAPI GetEnvironmentStringsA();
|
||||||
|
GUEST_PTR WINAPI GetEnvironmentStringsW();
|
||||||
BOOL WINAPI FreeEnvironmentStringsA(LPCH penv);
|
BOOL WINAPI FreeEnvironmentStringsA(LPCH penv);
|
||||||
BOOL WINAPI FreeEnvironmentStringsW(LPWCH penv);
|
BOOL WINAPI FreeEnvironmentStringsW(LPWCH penv);
|
||||||
DWORD WINAPI GetEnvironmentVariableA(LPCSTR lpName, LPSTR lpBuffer, DWORD nSize);
|
DWORD WINAPI GetEnvironmentVariableA(LPCSTR lpName, LPSTR lpBuffer, DWORD nSize);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "strutil.h"
|
#include "strutil.h"
|
||||||
#include "timeutil.h"
|
#include "timeutil.h"
|
||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <csignal>
|
#include <csignal>
|
||||||
@@ -83,7 +84,7 @@ template <typename StartupInfo> void populateStartupInfo(StartupInfo *info) {
|
|||||||
info->dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
|
info->dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
|
||||||
info->wShowWindow = SW_SHOWNORMAL;
|
info->wShowWindow = SW_SHOWNORMAL;
|
||||||
info->cbReserved2 = 0;
|
info->cbReserved2 = 0;
|
||||||
info->lpReserved2 = nullptr;
|
info->lpReserved2 = GUEST_NULL;
|
||||||
info->hStdInput = files::getStdHandle(STD_INPUT_HANDLE);
|
info->hStdInput = files::getStdHandle(STD_INPUT_HANDLE);
|
||||||
info->hStdOutput = files::getStdHandle(STD_OUTPUT_HANDLE);
|
info->hStdOutput = files::getStdHandle(STD_OUTPUT_HANDLE);
|
||||||
info->hStdError = files::getStdHandle(STD_ERROR_HANDLE);
|
info->hStdError = files::getStdHandle(STD_ERROR_HANDLE);
|
||||||
@@ -182,7 +183,7 @@ BOOL WINAPI IsProcessorFeaturePresent(DWORD ProcessorFeature) {
|
|||||||
HANDLE WINAPI GetCurrentProcess() {
|
HANDLE WINAPI GetCurrentProcess() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("GetCurrentProcess() -> %p\n", reinterpret_cast<void *>(static_cast<uintptr_t>(-1)));
|
DEBUG_LOG("GetCurrentProcess() -> %p\n", reinterpret_cast<void *>(static_cast<uintptr_t>(-1)));
|
||||||
return reinterpret_cast<HANDLE>(static_cast<uintptr_t>(-1));
|
return kPseudoCurrentProcessHandleValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD WINAPI GetCurrentProcessId() {
|
DWORD WINAPI GetCurrentProcessId() {
|
||||||
@@ -395,9 +396,9 @@ LPVOID WINAPI TlsGetValue(DWORD dwTlsIndex) {
|
|||||||
setLastError(ERROR_INVALID_PARAMETER);
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
void *result = wibo::tls::getValue(dwTlsIndex);
|
GUEST_PTR result = wibo::tls::getValue(dwTlsIndex);
|
||||||
setLastError(ERROR_SUCCESS);
|
setLastError(ERROR_SUCCESS);
|
||||||
return result;
|
return reinterpret_cast<LPVOID>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI TlsSetValue(DWORD dwTlsIndex, LPVOID lpTlsValue) {
|
BOOL WINAPI TlsSetValue(DWORD dwTlsIndex, LPVOID lpTlsValue) {
|
||||||
@@ -407,7 +408,7 @@ BOOL WINAPI TlsSetValue(DWORD dwTlsIndex, LPVOID lpTlsValue) {
|
|||||||
setLastError(ERROR_INVALID_PARAMETER);
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (!wibo::tls::setValue(dwTlsIndex, lpTlsValue)) {
|
if (!wibo::tls::setValue(dwTlsIndex, toGuestPtr(lpTlsValue))) {
|
||||||
setLastError(ERROR_INVALID_PARAMETER);
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
@@ -463,7 +464,7 @@ HANDLE WINAPI CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwSt
|
|||||||
if ((dwCreationFlags & ~SUPPORTED_FLAGS) != 0) {
|
if ((dwCreationFlags & ~SUPPORTED_FLAGS) != 0) {
|
||||||
DEBUG_LOG("CreateThread: unsupported creation flags 0x%x\n", dwCreationFlags);
|
DEBUG_LOG("CreateThread: unsupported creation flags 0x%x\n", dwCreationFlags);
|
||||||
setLastError(ERROR_NOT_SUPPORTED);
|
setLastError(ERROR_NOT_SUPPORTED);
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
Pin<ThreadObject> obj = make_pin<ThreadObject>(0); // tid set during pthread_create
|
Pin<ThreadObject> obj = make_pin<ThreadObject>(0); // tid set during pthread_create
|
||||||
@@ -554,7 +555,7 @@ int WINAPI GetThreadPriority(HANDLE hThread) {
|
|||||||
|
|
||||||
DWORD WINAPI GetPriorityClass(HANDLE hProcess) {
|
DWORD WINAPI GetPriorityClass(HANDLE hProcess) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("GetPriorityClass(%p)\n", hProcess);
|
DEBUG_LOG("STUB: GetPriorityClass(%p)\n", hProcess);
|
||||||
(void)hProcess;
|
(void)hProcess;
|
||||||
return NORMAL_PRIORITY_CLASS;
|
return NORMAL_PRIORITY_CLASS;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,9 +15,9 @@ using LPPROCESS_INFORMATION = PROCESS_INFORMATION *;
|
|||||||
|
|
||||||
struct STARTUPINFOA {
|
struct STARTUPINFOA {
|
||||||
DWORD cb;
|
DWORD cb;
|
||||||
LPSTR lpReserved;
|
GUEST_PTR lpReserved;
|
||||||
LPSTR lpDesktop;
|
GUEST_PTR lpDesktop;
|
||||||
LPSTR lpTitle;
|
GUEST_PTR lpTitle;
|
||||||
DWORD dwX;
|
DWORD dwX;
|
||||||
DWORD dwY;
|
DWORD dwY;
|
||||||
DWORD dwXSize;
|
DWORD dwXSize;
|
||||||
@@ -28,7 +28,7 @@ struct STARTUPINFOA {
|
|||||||
DWORD dwFlags;
|
DWORD dwFlags;
|
||||||
WORD wShowWindow;
|
WORD wShowWindow;
|
||||||
WORD cbReserved2;
|
WORD cbReserved2;
|
||||||
LPBYTE lpReserved2;
|
GUEST_PTR lpReserved2;
|
||||||
HANDLE hStdInput;
|
HANDLE hStdInput;
|
||||||
HANDLE hStdOutput;
|
HANDLE hStdOutput;
|
||||||
HANDLE hStdError;
|
HANDLE hStdError;
|
||||||
@@ -38,9 +38,9 @@ using LPSTARTUPINFOA = STARTUPINFOA *;
|
|||||||
|
|
||||||
struct STARTUPINFOW {
|
struct STARTUPINFOW {
|
||||||
DWORD cb;
|
DWORD cb;
|
||||||
LPWSTR lpReserved;
|
GUEST_PTR lpReserved;
|
||||||
LPWSTR lpDesktop;
|
GUEST_PTR lpDesktop;
|
||||||
LPWSTR lpTitle;
|
GUEST_PTR lpTitle;
|
||||||
DWORD dwX;
|
DWORD dwX;
|
||||||
DWORD dwY;
|
DWORD dwY;
|
||||||
DWORD dwXSize;
|
DWORD dwXSize;
|
||||||
@@ -51,7 +51,7 @@ struct STARTUPINFOW {
|
|||||||
DWORD dwFlags;
|
DWORD dwFlags;
|
||||||
WORD wShowWindow;
|
WORD wShowWindow;
|
||||||
WORD cbReserved2;
|
WORD cbReserved2;
|
||||||
LPBYTE lpReserved2;
|
GUEST_PTR lpReserved2;
|
||||||
HANDLE hStdInput;
|
HANDLE hStdInput;
|
||||||
HANDLE hStdOutput;
|
HANDLE hStdOutput;
|
||||||
HANDLE hStdError;
|
HANDLE hStdError;
|
||||||
|
|||||||
@@ -4,8 +4,10 @@
|
|||||||
#include "context.h"
|
#include "context.h"
|
||||||
#include "errors.h"
|
#include "errors.h"
|
||||||
#include "handles.h"
|
#include "handles.h"
|
||||||
|
#include "heap.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
#include "strutil.h"
|
#include "strutil.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
@@ -158,7 +160,7 @@ HANDLE WINAPI CreateMutexW(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitia
|
|||||||
if (!mu) {
|
if (!mu) {
|
||||||
// Name exists but isn't a mutex
|
// Name exists but isn't a mutex
|
||||||
setLastError(ERROR_INVALID_HANDLE);
|
setLastError(ERROR_INVALID_HANDLE);
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
HANDLE h = wibo::handles().alloc(std::move(mu), grantedAccess, handleFlags);
|
HANDLE h = wibo::handles().alloc(std::move(mu), grantedAccess, handleFlags);
|
||||||
setLastError(created ? ERROR_SUCCESS : ERROR_ALREADY_EXISTS);
|
setLastError(created ? ERROR_SUCCESS : ERROR_ALREADY_EXISTS);
|
||||||
@@ -204,7 +206,7 @@ BOOL WINAPI ReleaseMutex(HANDLE hMutex) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
|
HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
|
||||||
LPCWSTR lpName) {
|
LPCWSTR lpName) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("CreateEventW(%p, %d, %d, %s)\n", lpEventAttributes, static_cast<int>(bManualReset),
|
DEBUG_LOG("CreateEventW(%p, %d, %d, %s)\n", lpEventAttributes, static_cast<int>(bManualReset),
|
||||||
static_cast<int>(bInitialState), wideStringToString(lpName).c_str());
|
static_cast<int>(bInitialState), wideStringToString(lpName).c_str());
|
||||||
@@ -222,7 +224,7 @@ HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManual
|
|||||||
if (!ev) {
|
if (!ev) {
|
||||||
// Name exists but isn't an event
|
// Name exists but isn't an event
|
||||||
setLastError(ERROR_INVALID_HANDLE);
|
setLastError(ERROR_INVALID_HANDLE);
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
HANDLE h = wibo::handles().alloc(std::move(ev), grantedAccess, handleFlags);
|
HANDLE h = wibo::handles().alloc(std::move(ev), grantedAccess, handleFlags);
|
||||||
DEBUG_LOG("-> %p (created=%d)\n", h, created ? 1 : 0);
|
DEBUG_LOG("-> %p (created=%d)\n", h, created ? 1 : 0);
|
||||||
@@ -231,7 +233,7 @@ HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManual
|
|||||||
}
|
}
|
||||||
|
|
||||||
HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
|
HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
|
||||||
LPCSTR lpName) {
|
LPCSTR lpName) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("CreateEventA -> ");
|
DEBUG_LOG("CreateEventA -> ");
|
||||||
std::vector<uint16_t> wideName;
|
std::vector<uint16_t> wideName;
|
||||||
@@ -241,7 +243,7 @@ HANDLE WINAPI CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManual
|
|||||||
}
|
}
|
||||||
|
|
||||||
HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount,
|
HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount,
|
||||||
LPCWSTR lpName) {
|
LPCWSTR lpName) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("CreateSemaphoreW(%p, %ld, %ld, %s)\n", lpSemaphoreAttributes, lInitialCount, lMaximumCount,
|
DEBUG_LOG("CreateSemaphoreW(%p, %ld, %ld, %s)\n", lpSemaphoreAttributes, lInitialCount, lMaximumCount,
|
||||||
wideStringToString(lpName).c_str());
|
wideStringToString(lpName).c_str());
|
||||||
@@ -260,7 +262,7 @@ HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG
|
|||||||
if (!sem) {
|
if (!sem) {
|
||||||
// Name exists but isn't an event
|
// Name exists but isn't an event
|
||||||
setLastError(ERROR_INVALID_HANDLE);
|
setLastError(ERROR_INVALID_HANDLE);
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
HANDLE h = wibo::handles().alloc(std::move(sem), granted, hflags);
|
HANDLE h = wibo::handles().alloc(std::move(sem), granted, hflags);
|
||||||
setLastError(created ? ERROR_SUCCESS : ERROR_ALREADY_EXISTS);
|
setLastError(created ? ERROR_SUCCESS : ERROR_ALREADY_EXISTS);
|
||||||
@@ -268,7 +270,7 @@ HANDLE WINAPI CreateSemaphoreW(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG
|
|||||||
}
|
}
|
||||||
|
|
||||||
HANDLE WINAPI CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount,
|
HANDLE WINAPI CreateSemaphoreA(LPSECURITY_ATTRIBUTES lpSemaphoreAttributes, LONG lInitialCount, LONG lMaximumCount,
|
||||||
LPCSTR lpName) {
|
LPCSTR lpName) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("CreateSemaphoreA -> ");
|
DEBUG_LOG("CreateSemaphoreA -> ");
|
||||||
std::vector<uint16_t> wideName;
|
std::vector<uint16_t> wideName;
|
||||||
@@ -545,38 +547,37 @@ DWORD WINAPI WaitForMultipleObjects(DWORD nCount, const HANDLE *lpHandles, BOOL
|
|||||||
|
|
||||||
void WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) {
|
void WINAPI InitializeCriticalSection(LPCRITICAL_SECTION lpCriticalSection) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("STUB: InitializeCriticalSection(%p)\n", lpCriticalSection);
|
VERBOSE_LOG("InitializeCriticalSection(%p)\n", lpCriticalSection);
|
||||||
if (!lpCriticalSection) {
|
InitializeCriticalSectionEx(lpCriticalSection, 0, 0);
|
||||||
return;
|
|
||||||
}
|
|
||||||
std::memset(lpCriticalSection, 0, sizeof(*lpCriticalSection));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags) {
|
BOOL WINAPI InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("STUB: InitializeCriticalSectionEx(%p, %u, 0x%x)\n", lpCriticalSection, dwSpinCount, Flags);
|
DEBUG_LOG("InitializeCriticalSectionEx(%p, %u, 0x%x)\n", lpCriticalSection, dwSpinCount, Flags);
|
||||||
if (!lpCriticalSection) {
|
if (!lpCriticalSection) {
|
||||||
setLastError(ERROR_INVALID_PARAMETER);
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
if (Flags & ~CRITICAL_SECTION_NO_DEBUG_INFO) {
|
|
||||||
setLastError(ERROR_INVALID_PARAMETER);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
std::memset(lpCriticalSection, 0, sizeof(*lpCriticalSection));
|
std::memset(lpCriticalSection, 0, sizeof(*lpCriticalSection));
|
||||||
|
if (Flags & RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO) {
|
||||||
|
lpCriticalSection->DebugInfo = static_cast<GUEST_PTR>(-1);
|
||||||
|
} else {
|
||||||
|
auto *debugInfo = reinterpret_cast<RTL_CRITICAL_SECTION_DEBUG *>(
|
||||||
|
wibo::heap::guestCalloc(1, sizeof(RTL_CRITICAL_SECTION_DEBUG)));
|
||||||
|
debugInfo->CriticalSection = toGuestPtr(lpCriticalSection);
|
||||||
|
debugInfo->ProcessLocksList.Blink = toGuestPtr(&debugInfo->ProcessLocksList);
|
||||||
|
debugInfo->ProcessLocksList.Flink = toGuestPtr(&debugInfo->ProcessLocksList);
|
||||||
|
lpCriticalSection->DebugInfo = toGuestPtr(debugInfo);
|
||||||
|
}
|
||||||
|
lpCriticalSection->LockCount = -1;
|
||||||
lpCriticalSection->SpinCount = dwSpinCount;
|
lpCriticalSection->SpinCount = dwSpinCount;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount) {
|
BOOL WINAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("STUB: InitializeCriticalSectionAndSpinCount(%p, %u)\n", lpCriticalSection, dwSpinCount);
|
DEBUG_LOG("InitializeCriticalSectionAndSpinCount(%p, %u)\n", lpCriticalSection, dwSpinCount);
|
||||||
if (!lpCriticalSection) {
|
InitializeCriticalSectionEx(lpCriticalSection, dwSpinCount, 0);
|
||||||
setLastError(ERROR_INVALID_PARAMETER);
|
|
||||||
return FALSE;
|
|
||||||
}
|
|
||||||
std::memset(lpCriticalSection, 0, sizeof(*lpCriticalSection));
|
|
||||||
lpCriticalSection->SpinCount = dwSpinCount;
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -598,7 +599,7 @@ void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection) {
|
|||||||
(void)lpCriticalSection;
|
(void)lpCriticalSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, LPVOID *lpContext) {
|
BOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, GUEST_PTR *lpContext) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("STUB: InitOnceBeginInitialize(%p, %u, %p, %p)\n", lpInitOnce, dwFlags, fPending, lpContext);
|
DEBUG_LOG("STUB: InitOnceBeginInitialize(%p, %u, %p, %p)\n", lpInitOnce, dwFlags, fPending, lpContext);
|
||||||
if (!lpInitOnce) {
|
if (!lpInitOnce) {
|
||||||
@@ -613,7 +614,7 @@ BOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL
|
|||||||
*fPending = TRUE;
|
*fPending = TRUE;
|
||||||
}
|
}
|
||||||
if (lpContext) {
|
if (lpContext) {
|
||||||
*lpContext = nullptr;
|
*lpContext = GUEST_NULL;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,14 +15,20 @@ constexpr DWORD INIT_ONCE_ASYNC = 0x00000002UL;
|
|||||||
constexpr DWORD INIT_ONCE_INIT_FAILED = 0x00000004UL;
|
constexpr DWORD INIT_ONCE_INIT_FAILED = 0x00000004UL;
|
||||||
constexpr DWORD INIT_ONCE_CTX_RESERVED_BITS = 2;
|
constexpr DWORD INIT_ONCE_CTX_RESERVED_BITS = 2;
|
||||||
|
|
||||||
constexpr DWORD CRITICAL_SECTION_NO_DEBUG_INFO = 0x01000000UL;
|
constexpr DWORD RTL_CRITICAL_SECTION_FLAG_NO_DEBUG_INFO = 0x01000000UL;
|
||||||
|
constexpr DWORD RTL_CRITICAL_SECTION_FLAG_DYNAMIC_SPIN = 0x02000000UL;
|
||||||
|
constexpr DWORD RTL_CRITICAL_SECTION_FLAG_STATIC_INIT = 0x04000000UL;
|
||||||
|
constexpr DWORD RTL_CRITICAL_SECTION_FLAG_RESOURCE_TYPE = 0x08000000UL;
|
||||||
|
constexpr DWORD RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO = 0x10000000UL;
|
||||||
|
constexpr DWORD RTL_CRITICAL_SECTION_ALL_FLAG_BITS = 0xff000000UL;
|
||||||
|
constexpr DWORD RTL_CRITICAL_SECTION_FLAG_RESERVED = 0xe0000000UL;
|
||||||
|
|
||||||
struct RTL_CRITICAL_SECTION;
|
struct RTL_CRITICAL_SECTION;
|
||||||
|
|
||||||
struct RTL_CRITICAL_SECTION_DEBUG {
|
struct RTL_CRITICAL_SECTION_DEBUG {
|
||||||
WORD Type;
|
WORD Type;
|
||||||
WORD CreatorBackTraceIndex;
|
WORD CreatorBackTraceIndex;
|
||||||
RTL_CRITICAL_SECTION *CriticalSection;
|
GUEST_PTR CriticalSection;
|
||||||
LIST_ENTRY ProcessLocksList;
|
LIST_ENTRY ProcessLocksList;
|
||||||
DWORD EntryCount;
|
DWORD EntryCount;
|
||||||
DWORD ContentionCount;
|
DWORD ContentionCount;
|
||||||
@@ -33,7 +39,7 @@ struct RTL_CRITICAL_SECTION_DEBUG {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct RTL_CRITICAL_SECTION {
|
struct RTL_CRITICAL_SECTION {
|
||||||
RTL_CRITICAL_SECTION_DEBUG *DebugInfo;
|
GUEST_PTR DebugInfo;
|
||||||
LONG LockCount;
|
LONG LockCount;
|
||||||
LONG RecursionCount;
|
LONG RecursionCount;
|
||||||
HANDLE OwningThread;
|
HANDLE OwningThread;
|
||||||
@@ -47,7 +53,7 @@ using PCRITICAL_SECTION = RTL_CRITICAL_SECTION *;
|
|||||||
using PRTL_CRITICAL_SECTION_DEBUG = RTL_CRITICAL_SECTION_DEBUG *;
|
using PRTL_CRITICAL_SECTION_DEBUG = RTL_CRITICAL_SECTION_DEBUG *;
|
||||||
|
|
||||||
union RTL_RUN_ONCE {
|
union RTL_RUN_ONCE {
|
||||||
PVOID Ptr;
|
GUEST_PTR Ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
using PRTL_RUN_ONCE = RTL_RUN_ONCE *;
|
using PRTL_RUN_ONCE = RTL_RUN_ONCE *;
|
||||||
@@ -55,17 +61,17 @@ using INIT_ONCE = RTL_RUN_ONCE;
|
|||||||
using PINIT_ONCE = INIT_ONCE *;
|
using PINIT_ONCE = INIT_ONCE *;
|
||||||
using LPINIT_ONCE = INIT_ONCE *;
|
using LPINIT_ONCE = INIT_ONCE *;
|
||||||
|
|
||||||
constexpr INIT_ONCE INIT_ONCE_STATIC_INIT{nullptr};
|
constexpr INIT_ONCE INIT_ONCE_STATIC_INIT{GUEST_NULL};
|
||||||
|
|
||||||
union RTL_SRWLOCK {
|
union RTL_SRWLOCK {
|
||||||
PVOID Ptr;
|
GUEST_PTR Ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
using SRWLOCK = RTL_SRWLOCK;
|
using SRWLOCK = RTL_SRWLOCK;
|
||||||
using PSRWLOCK = SRWLOCK *;
|
using PSRWLOCK = SRWLOCK *;
|
||||||
using PRTL_SRWLOCK = SRWLOCK *;
|
using PRTL_SRWLOCK = SRWLOCK *;
|
||||||
|
|
||||||
constexpr SRWLOCK SRWLOCK_INIT{nullptr};
|
constexpr SRWLOCK SRWLOCK_INIT{GUEST_NULL};
|
||||||
|
|
||||||
namespace kernel32 {
|
namespace kernel32 {
|
||||||
|
|
||||||
@@ -92,7 +98,7 @@ BOOL WINAPI InitializeCriticalSectionAndSpinCount(LPCRITICAL_SECTION lpCriticalS
|
|||||||
void WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
|
void WINAPI DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
|
||||||
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
|
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
|
||||||
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
|
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION lpCriticalSection);
|
||||||
BOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, LPVOID *lpContext);
|
BOOL WINAPI InitOnceBeginInitialize(LPINIT_ONCE lpInitOnce, DWORD dwFlags, PBOOL fPending, GUEST_PTR *lpContext);
|
||||||
BOOL WINAPI InitOnceComplete(LPINIT_ONCE lpInitOnce, DWORD dwFlags, LPVOID lpContext);
|
BOOL WINAPI InitOnceComplete(LPINIT_ONCE lpInitOnce, DWORD dwFlags, LPVOID lpContext);
|
||||||
void WINAPI AcquireSRWLockShared(PSRWLOCK SRWLock);
|
void WINAPI AcquireSRWLockShared(PSRWLOCK SRWLock);
|
||||||
void WINAPI ReleaseSRWLockShared(PSRWLOCK SRWLock);
|
void WINAPI ReleaseSRWLockShared(PSRWLOCK SRWLock);
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "context.h"
|
#include "context.h"
|
||||||
#include "errors.h"
|
#include "errors.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "ntdll.h"
|
||||||
#include "timeutil.h"
|
#include "timeutil.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -52,12 +53,12 @@ void WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo) {
|
|||||||
}
|
}
|
||||||
lpSystemInfo->dwPageSize = static_cast<DWORD>(pageSize);
|
lpSystemInfo->dwPageSize = static_cast<DWORD>(pageSize);
|
||||||
|
|
||||||
lpSystemInfo->lpMinimumApplicationAddress = reinterpret_cast<LPVOID>(0x00010000);
|
lpSystemInfo->lpMinimumApplicationAddress = toGuestPtr(reinterpret_cast<void *>(0x00010000));
|
||||||
if (sizeof(void *) == 4) {
|
#ifdef _WIN64
|
||||||
lpSystemInfo->lpMaximumApplicationAddress = reinterpret_cast<LPVOID>(0x7FFEFFFF);
|
lpSystemInfo->lpMaximumApplicationAddress = toGuestPtr(reinterpret_cast<void *>(0x00007FFFFFFEFFFFull));
|
||||||
} else {
|
#else
|
||||||
lpSystemInfo->lpMaximumApplicationAddress = reinterpret_cast<LPVOID>(0x00007FFFFFFEFFFFull);
|
lpSystemInfo->lpMaximumApplicationAddress = toGuestPtr(reinterpret_cast<void *>(0x7FFEFFFF));
|
||||||
}
|
#endif
|
||||||
|
|
||||||
unsigned int cpuCount = 1;
|
unsigned int cpuCount = 1;
|
||||||
long reported = sysconf(_SC_NPROCESSORS_ONLN);
|
long reported = sysconf(_SC_NPROCESSORS_ONLN);
|
||||||
@@ -198,11 +199,62 @@ BOOL WINAPI GetVersionExA(LPOSVERSIONINFOA lpVersionInformation) {
|
|||||||
setLastError(ERROR_INVALID_PARAMETER);
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
std::memset(lpVersionInformation, 0, lpVersionInformation->dwOSVersionInfoSize);
|
|
||||||
lpVersionInformation->dwMajorVersion = kMajorVersion;
|
DWORD size = lpVersionInformation->dwOSVersionInfoSize;
|
||||||
lpVersionInformation->dwMinorVersion = kMinorVersion;
|
if (size < sizeof(OSVERSIONINFOA)) {
|
||||||
lpVersionInformation->dwBuildNumber = kBuildNumber;
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
lpVersionInformation->dwPlatformId = 2;
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD requestSize = (size >= sizeof(OSVERSIONINFOEXA)) ? sizeof(OSVERSIONINFOEXW) : sizeof(OSVERSIONINFOW);
|
||||||
|
OSVERSIONINFOEXW wideInfo{};
|
||||||
|
wideInfo.dwOSVersionInfoSize = requestSize;
|
||||||
|
NTSTATUS status = ntdll::RtlGetVersion(reinterpret_cast<PRTL_OSVERSIONINFOW>(&wideInfo));
|
||||||
|
if (status != STATUS_SUCCESS) {
|
||||||
|
setLastError(wibo::winErrorFromNtStatus(status));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memset(lpVersionInformation, 0, size);
|
||||||
|
lpVersionInformation->dwOSVersionInfoSize = size;
|
||||||
|
lpVersionInformation->dwMajorVersion = wideInfo.dwMajorVersion;
|
||||||
|
lpVersionInformation->dwMinorVersion = wideInfo.dwMinorVersion;
|
||||||
|
lpVersionInformation->dwBuildNumber = wideInfo.dwBuildNumber;
|
||||||
|
lpVersionInformation->dwPlatformId = wideInfo.dwPlatformId;
|
||||||
|
|
||||||
|
if (size >= sizeof(OSVERSIONINFOEXA)) {
|
||||||
|
auto extended = reinterpret_cast<OSVERSIONINFOEXA *>(lpVersionInformation);
|
||||||
|
extended->wServicePackMajor = wideInfo.wServicePackMajor;
|
||||||
|
extended->wServicePackMinor = wideInfo.wServicePackMinor;
|
||||||
|
extended->wSuiteMask = wideInfo.wSuiteMask;
|
||||||
|
extended->wProductType = wideInfo.wProductType;
|
||||||
|
extended->wReserved = wideInfo.wReserved;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL WINAPI GetVersionExW(LPOSVERSIONINFOW lpVersionInformation) {
|
||||||
|
HOST_CONTEXT_GUARD();
|
||||||
|
DEBUG_LOG("GetVersionExW(%p)\n", lpVersionInformation);
|
||||||
|
if (!lpVersionInformation) {
|
||||||
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD size = lpVersionInformation->dwOSVersionInfoSize;
|
||||||
|
if (size < sizeof(OSVERSIONINFOW)) {
|
||||||
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
NTSTATUS status = ntdll::RtlGetVersion(reinterpret_cast<PRTL_OSVERSIONINFOW>(lpVersionInformation));
|
||||||
|
if (status != STATUS_SUCCESS) {
|
||||||
|
setLastError(wibo::winErrorFromNtStatus(status));
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
lpVersionInformation->dwOSVersionInfoSize = size;
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ struct SYSTEM_INFO {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
DWORD dwPageSize;
|
DWORD dwPageSize;
|
||||||
LPVOID lpMinimumApplicationAddress;
|
GUEST_PTR lpMinimumApplicationAddress;
|
||||||
LPVOID lpMaximumApplicationAddress;
|
GUEST_PTR lpMaximumApplicationAddress;
|
||||||
DWORD_PTR dwActiveProcessorMask;
|
DWORD_PTR dwActiveProcessorMask;
|
||||||
DWORD dwNumberOfProcessors;
|
DWORD dwNumberOfProcessors;
|
||||||
DWORD dwProcessorType;
|
DWORD dwProcessorType;
|
||||||
@@ -35,6 +35,37 @@ struct OSVERSIONINFOA {
|
|||||||
|
|
||||||
using LPOSVERSIONINFOA = OSVERSIONINFOA *;
|
using LPOSVERSIONINFOA = OSVERSIONINFOA *;
|
||||||
|
|
||||||
|
struct OSVERSIONINFOW {
|
||||||
|
DWORD dwOSVersionInfoSize;
|
||||||
|
DWORD dwMajorVersion;
|
||||||
|
DWORD dwMinorVersion;
|
||||||
|
DWORD dwBuildNumber;
|
||||||
|
DWORD dwPlatformId;
|
||||||
|
WCHAR szCSDVersion[128];
|
||||||
|
};
|
||||||
|
|
||||||
|
using LPOSVERSIONINFOW = OSVERSIONINFOW *;
|
||||||
|
|
||||||
|
struct OSVERSIONINFOEXA : OSVERSIONINFOA {
|
||||||
|
WORD wServicePackMajor;
|
||||||
|
WORD wServicePackMinor;
|
||||||
|
WORD wSuiteMask;
|
||||||
|
BYTE wProductType;
|
||||||
|
BYTE wReserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
using LPOSVERSIONINFOEXA = OSVERSIONINFOEXA *;
|
||||||
|
|
||||||
|
struct OSVERSIONINFOEXW : OSVERSIONINFOW {
|
||||||
|
WORD wServicePackMajor;
|
||||||
|
WORD wServicePackMinor;
|
||||||
|
WORD wSuiteMask;
|
||||||
|
BYTE wProductType;
|
||||||
|
BYTE wReserved;
|
||||||
|
};
|
||||||
|
|
||||||
|
using LPOSVERSIONINFOEXW = OSVERSIONINFOEXW *;
|
||||||
|
|
||||||
namespace kernel32 {
|
namespace kernel32 {
|
||||||
|
|
||||||
void WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo);
|
void WINAPI GetSystemInfo(LPSYSTEM_INFO lpSystemInfo);
|
||||||
@@ -44,5 +75,6 @@ void WINAPI GetSystemTimeAsFileTime(LPFILETIME lpSystemTimeAsFileTime);
|
|||||||
DWORD WINAPI GetTickCount();
|
DWORD WINAPI GetTickCount();
|
||||||
DWORD WINAPI GetVersion();
|
DWORD WINAPI GetVersion();
|
||||||
BOOL WINAPI GetVersionExA(LPOSVERSIONINFOA lpVersionInformation);
|
BOOL WINAPI GetVersionExA(LPOSVERSIONINFOA lpVersionInformation);
|
||||||
|
BOOL WINAPI GetVersionExW(LPOSVERSIONINFOW lpVersionInformation);
|
||||||
|
|
||||||
} // namespace kernel32
|
} // namespace kernel32
|
||||||
|
|||||||
@@ -235,7 +235,7 @@ bool doFree(void *mem) {
|
|||||||
DEBUG_LOG("doFree(%p) -> virtualFree\n", mem);
|
DEBUG_LOG("doFree(%p) -> virtualFree\n", mem);
|
||||||
MEMORY_BASIC_INFORMATION info;
|
MEMORY_BASIC_INFORMATION info;
|
||||||
auto result = wibo::heap::virtualQuery(mem, &info);
|
auto result = wibo::heap::virtualQuery(mem, &info);
|
||||||
if (result != wibo::heap::VmStatus::Success || info.BaseAddress != mem) {
|
if (result != wibo::heap::VmStatus::Success || fromGuestPtr(info.BaseAddress) != mem) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
wibo::heap::virtualFree(mem, info.RegionSize, MEM_RELEASE);
|
wibo::heap::virtualFree(mem, info.RegionSize, MEM_RELEASE);
|
||||||
@@ -697,7 +697,7 @@ BOOL WINAPI FindActCtxSectionStringW(DWORD dwFlags, const GUID *lpExtensionGuid,
|
|||||||
ReturnedData->ulDataFormatVersion = 1;
|
ReturnedData->ulDataFormatVersion = 1;
|
||||||
ReturnedData->ulFlags = ACTCTX_SECTION_KEYED_DATA_FLAG_FOUND_IN_ACTCTX;
|
ReturnedData->ulFlags = ACTCTX_SECTION_KEYED_DATA_FLAG_FOUND_IN_ACTCTX;
|
||||||
if (dwFlags & FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX) {
|
if (dwFlags & FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX) {
|
||||||
ReturnedData->hActCtx = reinterpret_cast<HANDLE>(&g_builtinActCtx);
|
ReturnedData->hActCtx = toGuestPtr(&g_builtinActCtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!matchedEntry) {
|
if (!matchedEntry) {
|
||||||
@@ -705,9 +705,9 @@ BOOL WINAPI FindActCtxSectionStringW(DWORD dwFlags, const GUID *lpExtensionGuid,
|
|||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnedData->lpData = const_cast<ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION *>(&matchedEntry->dllData);
|
ReturnedData->lpData = toGuestPtr(&matchedEntry->dllData);
|
||||||
ReturnedData->ulLength = matchedEntry->dllData.Size;
|
ReturnedData->ulLength = matchedEntry->dllData.Size;
|
||||||
ReturnedData->lpSectionBase = const_cast<ACTIVATION_CONTEXT_DATA_DLL_REDIRECTION *>(&matchedEntry->dllData);
|
ReturnedData->lpSectionBase = toGuestPtr(&matchedEntry->dllData);
|
||||||
ReturnedData->ulSectionTotalLength = matchedEntry->dllData.Size;
|
ReturnedData->ulSectionTotalLength = matchedEntry->dllData.Size;
|
||||||
ReturnedData->ulAssemblyRosterIndex = 1;
|
ReturnedData->ulAssemblyRosterIndex = 1;
|
||||||
ReturnedData->AssemblyMetadata = {};
|
ReturnedData->AssemblyMetadata = {};
|
||||||
@@ -805,20 +805,20 @@ HGLOBAL WINAPI GlobalAlloc(UINT uFlags, SIZE_T dwBytes) {
|
|||||||
if (uFlags & GMEM_MOVEABLE) {
|
if (uFlags & GMEM_MOVEABLE) {
|
||||||
// not implemented rn
|
// not implemented rn
|
||||||
assert(0);
|
assert(0);
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
bool zero = (uFlags & GMEM_ZEROINIT) != 0;
|
bool zero = (uFlags & GMEM_ZEROINIT) != 0;
|
||||||
void *ret = doAlloc(static_cast<UINT>(dwBytes), zero);
|
void *ret = doAlloc(static_cast<UINT>(dwBytes), zero);
|
||||||
DEBUG_LOG("-> %p\n", ret);
|
DEBUG_LOG("-> %p\n", ret);
|
||||||
return ret;
|
return toGuestPtr(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
HGLOBAL WINAPI GlobalFree(HGLOBAL hMem) {
|
HGLOBAL WINAPI GlobalFree(HGLOBAL hMem) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("GlobalFree(%p)\n", hMem);
|
VERBOSE_LOG("GlobalFree(%p)\n", hMem);
|
||||||
if (doFree(hMem)) {
|
if (doFree(reinterpret_cast<void *>(hMem))) {
|
||||||
DEBUG_LOG("-> success\n");
|
DEBUG_LOG("-> success\n");
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
} else {
|
} else {
|
||||||
DEBUG_LOG("-> failure\n");
|
DEBUG_LOG("-> failure\n");
|
||||||
return hMem;
|
return hMem;
|
||||||
@@ -830,12 +830,12 @@ HGLOBAL WINAPI GlobalReAlloc(HGLOBAL hMem, SIZE_T dwBytes, UINT uFlags) {
|
|||||||
VERBOSE_LOG("GlobalReAlloc(%p, %zu, %x)\n", hMem, static_cast<size_t>(dwBytes), uFlags);
|
VERBOSE_LOG("GlobalReAlloc(%p, %zu, %x)\n", hMem, static_cast<size_t>(dwBytes), uFlags);
|
||||||
if (uFlags & GMEM_MODIFY) {
|
if (uFlags & GMEM_MODIFY) {
|
||||||
assert(0);
|
assert(0);
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
bool zero = (uFlags & GMEM_ZEROINIT) != 0;
|
bool zero = (uFlags & GMEM_ZEROINIT) != 0;
|
||||||
void *ret = doRealloc(hMem, static_cast<UINT>(dwBytes), zero);
|
void *ret = doRealloc(reinterpret_cast<void *>(hMem), static_cast<UINT>(dwBytes), zero);
|
||||||
DEBUG_LOG("-> %p\n", ret);
|
DEBUG_LOG("-> %p\n", ret);
|
||||||
return ret;
|
return toGuestPtr(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT WINAPI GlobalFlags(HGLOBAL hMem) {
|
UINT WINAPI GlobalFlags(HGLOBAL hMem) {
|
||||||
@@ -855,20 +855,24 @@ HLOCAL WINAPI LocalAlloc(UINT uFlags, SIZE_T uBytes) {
|
|||||||
void *result = doAlloc(static_cast<UINT>(uBytes), zero);
|
void *result = doAlloc(static_cast<UINT>(uBytes), zero);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
setLastError(ERROR_NOT_SUPPORTED);
|
setLastError(ERROR_NOT_SUPPORTED);
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
// Legacy Windows applications (pre-NX and DEP) may expect executable memory from LocalAlloc.
|
// Legacy Windows applications (pre-NX and DEP) may expect executable memory from LocalAlloc.
|
||||||
tryMarkExecutable(result);
|
tryMarkExecutable(result);
|
||||||
DEBUG_LOG(" -> %p\n", result);
|
DEBUG_LOG(" -> %p\n", result);
|
||||||
return result;
|
return toGuestPtr(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
HLOCAL WINAPI LocalFree(HLOCAL hMem) {
|
HLOCAL WINAPI LocalFree(HLOCAL hMem) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("LocalFree(%p)\n", hMem);
|
VERBOSE_LOG("LocalFree(%p)\n", hMem);
|
||||||
// Windows returns NULL on success.
|
if (doFree(reinterpret_cast<void *>(hMem))) {
|
||||||
std::free(hMem);
|
DEBUG_LOG("-> success\n");
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
|
} else {
|
||||||
|
DEBUG_LOG("-> failure\n");
|
||||||
|
return hMem;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
HLOCAL WINAPI LocalReAlloc(HLOCAL hMem, SIZE_T uBytes, UINT uFlags) {
|
HLOCAL WINAPI LocalReAlloc(HLOCAL hMem, SIZE_T uBytes, UINT uFlags) {
|
||||||
@@ -878,27 +882,27 @@ HLOCAL WINAPI LocalReAlloc(HLOCAL hMem, SIZE_T uBytes, UINT uFlags) {
|
|||||||
if ((uFlags & LMEM_MOVEABLE) != 0) {
|
if ((uFlags & LMEM_MOVEABLE) != 0) {
|
||||||
DEBUG_LOG(" ignoring LMEM_MOVEABLE\n");
|
DEBUG_LOG(" ignoring LMEM_MOVEABLE\n");
|
||||||
}
|
}
|
||||||
void *result = doRealloc(hMem, static_cast<UINT>(uBytes), zero);
|
void *result = doRealloc(reinterpret_cast<void *>(hMem), static_cast<UINT>(uBytes), zero);
|
||||||
if (!result && uBytes != 0) {
|
if (!result && uBytes != 0) {
|
||||||
setLastError(ERROR_NOT_SUPPORTED);
|
setLastError(ERROR_NOT_SUPPORTED);
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
// Legacy Windows applications (pre-NX and DEP) may expect executable memory from LocalReAlloc.
|
// Legacy Windows applications (pre-NX and DEP) may expect executable memory from LocalReAlloc.
|
||||||
tryMarkExecutable(result);
|
tryMarkExecutable(result);
|
||||||
DEBUG_LOG(" -> %p\n", result);
|
DEBUG_LOG(" -> %p\n", result);
|
||||||
return result;
|
return toGuestPtr(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
HLOCAL WINAPI LocalHandle(LPCVOID pMem) {
|
HLOCAL WINAPI LocalHandle(LPCVOID pMem) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("LocalHandle(%p)\n", pMem);
|
VERBOSE_LOG("LocalHandle(%p)\n", pMem);
|
||||||
return const_cast<LPVOID>(pMem);
|
return toGuestPtr(pMem);
|
||||||
}
|
}
|
||||||
|
|
||||||
LPVOID WINAPI LocalLock(HLOCAL hMem) {
|
LPVOID WINAPI LocalLock(HLOCAL hMem) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("LocalLock(%p)\n", hMem);
|
VERBOSE_LOG("LocalLock(%p)\n", hMem);
|
||||||
return hMem;
|
return reinterpret_cast<void *>(hMem);
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI LocalUnlock(HLOCAL hMem) {
|
BOOL WINAPI LocalUnlock(HLOCAL hMem) {
|
||||||
@@ -911,7 +915,7 @@ BOOL WINAPI LocalUnlock(HLOCAL hMem) {
|
|||||||
SIZE_T WINAPI LocalSize(HLOCAL hMem) {
|
SIZE_T WINAPI LocalSize(HLOCAL hMem) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("LocalSize(%p)\n", hMem);
|
VERBOSE_LOG("LocalSize(%p)\n", hMem);
|
||||||
return hMem ? mi_usable_size(hMem) : 0;
|
return hMem ? mi_usable_size(reinterpret_cast<void *>(hMem)) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT WINAPI LocalFlags(HLOCAL hMem) {
|
UINT WINAPI LocalFlags(HLOCAL hMem) {
|
||||||
|
|||||||
@@ -5,21 +5,21 @@
|
|||||||
struct GUID;
|
struct GUID;
|
||||||
|
|
||||||
struct ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA {
|
struct ACTCTX_SECTION_KEYED_DATA_ASSEMBLY_METADATA {
|
||||||
PVOID lpInformation;
|
GUEST_PTR lpInformation;
|
||||||
PVOID lpSectionBase;
|
GUEST_PTR lpSectionBase;
|
||||||
ULONG ulSectionLength;
|
ULONG ulSectionLength;
|
||||||
PVOID lpSectionGlobalData;
|
GUEST_PTR lpSectionGlobalData;
|
||||||
ULONG ulSectionGlobalDataLength;
|
ULONG ulSectionGlobalDataLength;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ACTCTX_SECTION_KEYED_DATA {
|
struct ACTCTX_SECTION_KEYED_DATA {
|
||||||
ULONG cbSize;
|
ULONG cbSize;
|
||||||
ULONG ulDataFormatVersion;
|
ULONG ulDataFormatVersion;
|
||||||
PVOID lpData;
|
GUEST_PTR lpData;
|
||||||
ULONG ulLength;
|
ULONG ulLength;
|
||||||
PVOID lpSectionGlobalData;
|
GUEST_PTR lpSectionGlobalData;
|
||||||
ULONG ulSectionGlobalDataLength;
|
ULONG ulSectionGlobalDataLength;
|
||||||
PVOID lpSectionBase;
|
GUEST_PTR lpSectionBase;
|
||||||
ULONG ulSectionTotalLength;
|
ULONG ulSectionTotalLength;
|
||||||
HANDLE hActCtx;
|
HANDLE hActCtx;
|
||||||
ULONG ulAssemblyRosterIndex;
|
ULONG ulAssemblyRosterIndex;
|
||||||
@@ -68,8 +68,8 @@ ATOM WINAPI AddAtomW(LPCWSTR lpString);
|
|||||||
UINT WINAPI GetAtomNameA(ATOM nAtom, LPSTR lpBuffer, int nSize);
|
UINT WINAPI GetAtomNameA(ATOM nAtom, LPSTR lpBuffer, int nSize);
|
||||||
UINT WINAPI GetAtomNameW(ATOM nAtom, LPWSTR lpBuffer, int nSize);
|
UINT WINAPI GetAtomNameW(ATOM nAtom, LPWSTR lpBuffer, int nSize);
|
||||||
UINT WINAPI SetHandleCount(UINT uNumber);
|
UINT WINAPI SetHandleCount(UINT uNumber);
|
||||||
DWORD WINAPI FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer,
|
// DWORD WINAPI FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, DWORD dwLanguageId, LPSTR lpBuffer,
|
||||||
DWORD nSize, va_list *Arguments);
|
// DWORD nSize, va_list *Arguments);
|
||||||
PVOID WINAPI EncodePointer(PVOID Ptr);
|
PVOID WINAPI EncodePointer(PVOID Ptr);
|
||||||
PVOID WINAPI DecodePointer(PVOID Ptr);
|
PVOID WINAPI DecodePointer(PVOID Ptr);
|
||||||
BOOL WINAPI SetDllDirectoryA(LPCSTR lpPathName);
|
BOOL WINAPI SetDllDirectoryA(LPCSTR lpPathName);
|
||||||
|
|||||||
@@ -19,6 +19,9 @@ constexpr DWORD kNormIgnoreCase = 0x00000001;
|
|||||||
constexpr DWORD LCID_INSTALLED = 0x00000001;
|
constexpr DWORD LCID_INSTALLED = 0x00000001;
|
||||||
constexpr DWORD LCID_SUPPORTED = 0x00000002;
|
constexpr DWORD LCID_SUPPORTED = 0x00000002;
|
||||||
constexpr DWORD LCID_ALTERNATE_SORTS = 0x00000004;
|
constexpr DWORD LCID_ALTERNATE_SORTS = 0x00000004;
|
||||||
|
constexpr LCID kEnUsLcid = 0x0409;
|
||||||
|
constexpr LCID kInvariantLcid = 0x007f;
|
||||||
|
constexpr DWORD LOCALE_ALLOW_NEUTRAL_NAMES = 0x08000000;
|
||||||
|
|
||||||
int compareStrings(const std::string &a, const std::string &b, DWORD dwCmpFlags) {
|
int compareStrings(const std::string &a, const std::string &b, DWORD dwCmpFlags) {
|
||||||
for (size_t i = 0;; ++i) {
|
for (size_t i = 0;; ++i) {
|
||||||
@@ -102,6 +105,50 @@ LANGID WINAPI GetUserDefaultUILanguage() {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int WINAPI GetUserDefaultLocaleName(LPWSTR lpLocaleName, int cchLocaleName) {
|
||||||
|
HOST_CONTEXT_GUARD();
|
||||||
|
DEBUG_LOG("GetUserDefaultLocaleName(%p, %d)\n", lpLocaleName, cchLocaleName);
|
||||||
|
if (!lpLocaleName || cchLocaleName < 0) {
|
||||||
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr char16_t localeName[] = u"en-US";
|
||||||
|
constexpr int requiredChars = static_cast<int>(sizeof(localeName) / sizeof(char16_t));
|
||||||
|
if (cchLocaleName < requiredChars) {
|
||||||
|
setLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::memcpy(lpLocaleName, localeName, sizeof(localeName));
|
||||||
|
return requiredChars;
|
||||||
|
}
|
||||||
|
|
||||||
|
LCID WINAPI LocaleNameToLCID(LPCWSTR lpName, DWORD dwFlags) {
|
||||||
|
HOST_CONTEXT_GUARD();
|
||||||
|
DEBUG_LOG("LocaleNameToLCID(%p, 0x%x)\n", lpName, dwFlags);
|
||||||
|
if (dwFlags & ~LOCALE_ALLOW_NEUTRAL_NAMES) {
|
||||||
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (!lpName) {
|
||||||
|
return kEnUsLcid;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string localeName = wideStringToString(lpName);
|
||||||
|
if (localeName.empty()) {
|
||||||
|
return kInvariantLcid;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string normalized = stringToLower(localeName);
|
||||||
|
if (normalized == "en-us" || normalized == "en_us" || normalized == "!x-sys-default-locale") {
|
||||||
|
return kEnUsLcid;
|
||||||
|
}
|
||||||
|
|
||||||
|
setLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
BOOL WINAPI GetCPInfo(UINT CodePage, LPCPINFO lpCPInfo) {
|
BOOL WINAPI GetCPInfo(UINT CodePage, LPCPINFO lpCPInfo) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("GetCPInfo(%u, %p)\n", CodePage, lpCPInfo);
|
DEBUG_LOG("GetCPInfo(%u, %p)\n", CodePage, lpCPInfo);
|
||||||
@@ -120,7 +167,7 @@ BOOL WINAPI GetCPInfo(UINT CodePage, LPCPINFO lpCPInfo) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int WINAPI CompareStringA(LCID Locale, DWORD dwCmpFlags, LPCSTR lpString1, int cchCount1, LPCSTR lpString2,
|
int WINAPI CompareStringA(LCID Locale, DWORD dwCmpFlags, LPCSTR lpString1, int cchCount1, LPCSTR lpString2,
|
||||||
int cchCount2) {
|
int cchCount2) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("CompareStringA(%u, %u, %s, %d, %s, %d)\n", Locale, dwCmpFlags, lpString1 ? lpString1 : "(null)",
|
DEBUG_LOG("CompareStringA(%u, %u, %s, %d, %s, %d)\n", Locale, dwCmpFlags, lpString1 ? lpString1 : "(null)",
|
||||||
cchCount1, lpString2 ? lpString2 : "(null)", cchCount2);
|
cchCount1, lpString2 ? lpString2 : "(null)", cchCount2);
|
||||||
@@ -143,7 +190,7 @@ int WINAPI CompareStringA(LCID Locale, DWORD dwCmpFlags, LPCSTR lpString1, int c
|
|||||||
}
|
}
|
||||||
|
|
||||||
int WINAPI CompareStringW(LCID Locale, DWORD dwCmpFlags, LPCWCH lpString1, int cchCount1, LPCWCH lpString2,
|
int WINAPI CompareStringW(LCID Locale, DWORD dwCmpFlags, LPCWCH lpString1, int cchCount1, LPCWCH lpString2,
|
||||||
int cchCount2) {
|
int cchCount2) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("CompareStringW(%u, %u, %p, %d, %p, %d)\n", Locale, dwCmpFlags, lpString1, cchCount1, lpString2,
|
DEBUG_LOG("CompareStringW(%u, %u, %p, %d, %p, %d)\n", Locale, dwCmpFlags, lpString1, cchCount1, lpString2,
|
||||||
cchCount2);
|
cchCount2);
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ namespace kernel32 {
|
|||||||
UINT WINAPI GetACP();
|
UINT WINAPI GetACP();
|
||||||
LANGID WINAPI GetSystemDefaultLangID();
|
LANGID WINAPI GetSystemDefaultLangID();
|
||||||
LANGID WINAPI GetUserDefaultUILanguage();
|
LANGID WINAPI GetUserDefaultUILanguage();
|
||||||
|
int WINAPI GetUserDefaultLocaleName(LPWSTR lpLocaleName, int cchLocaleName);
|
||||||
|
LCID WINAPI LocaleNameToLCID(LPCWSTR lpName, DWORD dwFlags);
|
||||||
BOOL WINAPI GetCPInfo(UINT CodePage, LPCPINFO lpCPInfo);
|
BOOL WINAPI GetCPInfo(UINT CodePage, LPCPINFO lpCPInfo);
|
||||||
int WINAPI CompareStringA(LCID Locale, DWORD dwCmpFlags, LPCSTR lpString1, int cchCount1, LPCSTR lpString2,
|
int WINAPI CompareStringA(LCID Locale, DWORD dwCmpFlags, LPCSTR lpString1, int cchCount1, LPCSTR lpString2,
|
||||||
int cchCount2);
|
int cchCount2);
|
||||||
|
|||||||
@@ -5,14 +5,15 @@
|
|||||||
#include "errors.h"
|
#include "errors.h"
|
||||||
#include "handles.h"
|
#include "handles.h"
|
||||||
#include "internal.h"
|
#include "internal.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
namespace kernel32 {
|
namespace kernel32 {
|
||||||
|
|
||||||
BOOL WINAPI Wow64DisableWow64FsRedirection(PVOID *OldValue) {
|
BOOL WINAPI Wow64DisableWow64FsRedirection(GUEST_PTR *OldValue) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("STUB: Wow64DisableWow64FsRedirection(%p)\n", OldValue);
|
DEBUG_LOG("STUB: Wow64DisableWow64FsRedirection(%p)\n", OldValue);
|
||||||
if (OldValue) {
|
if (OldValue) {
|
||||||
*OldValue = nullptr;
|
*OldValue = GUEST_NULL;
|
||||||
}
|
}
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
namespace kernel32 {
|
namespace kernel32 {
|
||||||
|
|
||||||
BOOL WINAPI Wow64DisableWow64FsRedirection(PVOID *OldValue);
|
BOOL WINAPI Wow64DisableWow64FsRedirection(GUEST_PTR *OldValue);
|
||||||
BOOL WINAPI Wow64RevertWow64FsRedirection(PVOID OldValue);
|
BOOL WINAPI Wow64RevertWow64FsRedirection(PVOID OldValue);
|
||||||
BOOL WINAPI IsWow64Process(HANDLE hProcess, PBOOL Wow64Process);
|
BOOL WINAPI IsWow64Process(HANDLE hProcess, PBOOL Wow64Process);
|
||||||
|
|
||||||
|
|||||||
224
dll/msvcrt.cpp
224
dll/msvcrt.cpp
@@ -9,6 +9,7 @@
|
|||||||
#include "msvcrt_trampolines.h"
|
#include "msvcrt_trampolines.h"
|
||||||
#include "processes.h"
|
#include "processes.h"
|
||||||
#include "strutil.h"
|
#include "strutil.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
@@ -97,10 +98,10 @@ int closeGuestFile(_FILE *file) {
|
|||||||
namespace msvcrt {
|
namespace msvcrt {
|
||||||
int _commode;
|
int _commode;
|
||||||
int _fmode;
|
int _fmode;
|
||||||
char** __initenv;
|
GUEST_PTR __initenv = GUEST_NULL;
|
||||||
uint16_t** __winitenv;
|
GUEST_PTR __winitenv = GUEST_NULL;
|
||||||
uint16_t* _wpgmptr = nullptr;
|
GUEST_PTR _wpgmptr = GUEST_NULL;
|
||||||
char* _pgmptr = nullptr;
|
GUEST_PTR _pgmptr = GUEST_NULL;
|
||||||
int __mb_cur_max = 1;
|
int __mb_cur_max = 1;
|
||||||
_FILE _iob[_IOB_ENTRIES] = {_FILE{STDOUT_FILENO}, _FILE{STDERR_FILENO}, _FILE{STDIN_FILENO}};
|
_FILE _iob[_IOB_ENTRIES] = {_FILE{STDOUT_FILENO}, _FILE{STDERR_FILENO}, _FILE{STDIN_FILENO}};
|
||||||
|
|
||||||
@@ -381,11 +382,11 @@ namespace msvcrt {
|
|||||||
return mbCodePageSetting;
|
return mbCodePageSetting;
|
||||||
}
|
}
|
||||||
|
|
||||||
int* CDECL __p___mb_cur_max() {
|
GUEST_PTR CDECL __p___mb_cur_max() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
ensureMbctypeInitialized();
|
ensureMbctypeInitialized();
|
||||||
DEBUG_LOG("__p___mb_cur_max() -> %u\n", __mb_cur_max);
|
DEBUG_LOG("__p___mb_cur_max() -> %u\n", __mb_cur_max);
|
||||||
return &__mb_cur_max;
|
return toGuestPtr(&__mb_cur_max);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CDECL _setmbcp(int codepage) {
|
int CDECL _setmbcp(int codepage) {
|
||||||
@@ -414,19 +415,19 @@ namespace msvcrt {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned char *CDECL __p__mbctype() {
|
GUEST_PTR CDECL __p__mbctype() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
ensureMbctypeInitialized();
|
ensureMbctypeInitialized();
|
||||||
DEBUG_LOG("__p__mbctype() -> %p\n", mbctypeTable.data());
|
DEBUG_LOG("__p__mbctype() -> %p\n", mbctypeTable.data());
|
||||||
return mbctypeTable.data();
|
return toGuestPtr(mbctypeTable.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned short **CDECL __p__pctype() {
|
GUEST_PTR CDECL __p__pctype() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("__p__pctype()\n");
|
DEBUG_LOG("__p__pctype()\n");
|
||||||
static unsigned short *pointer = nullptr;
|
static unsigned short *pointer = nullptr;
|
||||||
pointer = pctypeTable().data() + 1;
|
pointer = pctypeTable().data() + 1;
|
||||||
return &pointer;
|
return toGuestPtr(&pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CDECL _isctype(int ch, int mask) {
|
int CDECL _isctype(int ch, int mask) {
|
||||||
@@ -502,11 +503,11 @@ namespace msvcrt {
|
|||||||
|
|
||||||
template <typename CharT>
|
template <typename CharT>
|
||||||
struct StringListStorage {
|
struct StringListStorage {
|
||||||
std::vector<std::unique_ptr<CharT[]>> strings;
|
std::vector<wibo::heap::guest_ptr<CharT[]>> strings;
|
||||||
std::unique_ptr<CharT*[]> pointers;
|
wibo::heap::guest_ptr<GUEST_PTR[]> pointers;
|
||||||
|
|
||||||
template <typename Converter>
|
template <typename Converter>
|
||||||
CharT **assign(char **source, Converter convert) {
|
GUEST_PTR *assign(char **source, Converter convert) {
|
||||||
if (!source) {
|
if (!source) {
|
||||||
strings.clear();
|
strings.clear();
|
||||||
pointers.reset();
|
pointers.reset();
|
||||||
@@ -520,18 +521,18 @@ namespace msvcrt {
|
|||||||
|
|
||||||
strings.clear();
|
strings.clear();
|
||||||
strings.reserve(count);
|
strings.reserve(count);
|
||||||
pointers = std::make_unique<CharT *[]>(count + 1);
|
pointers = wibo::heap::make_guest_unique<GUEST_PTR[]>(count + 1);
|
||||||
|
|
||||||
for (SIZE_T i = 0; i < count; ++i) {
|
for (SIZE_T i = 0; i < count; ++i) {
|
||||||
auto data = convert(source[i]);
|
auto data = convert(source[i]);
|
||||||
auto buffer = std::make_unique<CharT[]>(data.size());
|
auto buffer = wibo::heap::make_guest_unique<CharT[]>(data.size());
|
||||||
std::copy(data.begin(), data.end(), buffer.get());
|
std::copy(data.begin(), data.end(), buffer.get());
|
||||||
CharT *raw = buffer.get();
|
CharT *raw = buffer.get();
|
||||||
strings.emplace_back(std::move(buffer));
|
strings.emplace_back(std::move(buffer));
|
||||||
pointers[i] = raw;
|
pointers[i] = toGuestPtr(raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
pointers[count] = nullptr;
|
pointers[count] = GUEST_NULL;
|
||||||
return pointers.get();
|
return pointers.get();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -554,7 +555,7 @@ namespace msvcrt {
|
|||||||
|
|
||||||
template <typename CharT, typename Converter>
|
template <typename CharT, typename Converter>
|
||||||
// NOLINTNEXTLINE(readability-non-const-parameter)
|
// NOLINTNEXTLINE(readability-non-const-parameter)
|
||||||
int getMainArgsCommon(int *argcOut, CharT ***argvOut, CharT ***envOut, Converter convert) {
|
int getMainArgsCommon(int *argcOut, GUEST_PTR *argvOut, GUEST_PTR *envOut, Converter convert) {
|
||||||
if (argcOut) {
|
if (argcOut) {
|
||||||
*argcOut = wibo::argc;
|
*argcOut = wibo::argc;
|
||||||
}
|
}
|
||||||
@@ -563,18 +564,18 @@ namespace msvcrt {
|
|||||||
static StringListStorage<CharT> envStorage;
|
static StringListStorage<CharT> envStorage;
|
||||||
|
|
||||||
if (argvOut) {
|
if (argvOut) {
|
||||||
*argvOut = argvStorage.assign(wibo::argv, convert);
|
*argvOut = toGuestPtr(argvStorage.assign(wibo::argv, convert));
|
||||||
}
|
}
|
||||||
|
|
||||||
CharT **envData = envStorage.assign(environ, convert);
|
GUEST_PTR *envData = envStorage.assign(environ, convert);
|
||||||
if (envOut) {
|
if (envOut) {
|
||||||
*envOut = envData;
|
*envOut = toGuestPtr(envData);
|
||||||
}
|
}
|
||||||
|
|
||||||
if constexpr (std::is_same_v<CharT, uint16_t>) {
|
if constexpr (std::is_same_v<CharT, uint16_t>) {
|
||||||
__winitenv = envData;
|
__winitenv = toGuestPtr(envData);
|
||||||
} else if constexpr (std::is_same_v<CharT, char>) {
|
} else if constexpr (std::is_same_v<CharT, char>) {
|
||||||
__initenv = envData;
|
__initenv = toGuestPtr(envData);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -633,7 +634,7 @@ namespace msvcrt {
|
|||||||
if (!__winitenv) {
|
if (!__winitenv) {
|
||||||
getMainArgsCommon<uint16_t>(nullptr, nullptr, nullptr, copyWideString);
|
getMainArgsCommon<uint16_t>(nullptr, nullptr, nullptr, copyWideString);
|
||||||
}
|
}
|
||||||
return __winitenv;
|
return reinterpret_cast<uint16_t**>(__winitenv);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@@ -644,42 +645,44 @@ namespace msvcrt {
|
|||||||
(void)at;
|
(void)at;
|
||||||
}
|
}
|
||||||
|
|
||||||
int* CDECL __p__fmode() {
|
GUEST_PTR CDECL __p__fmode() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("__p__fmode() -> %p\n", &_fmode);
|
DEBUG_LOG("__p__fmode() -> %p\n", &_fmode);
|
||||||
return &_fmode;
|
return toGuestPtr(&_fmode);
|
||||||
}
|
}
|
||||||
|
|
||||||
int* CDECL __p__commode() {
|
GUEST_PTR CDECL __p__commode() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("__p__commode() -> %p\n", &_commode);
|
DEBUG_LOG("__p__commode() -> %p\n", &_commode);
|
||||||
return &_commode;
|
return toGuestPtr(&_commode);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDECL _initterm(const _PVFV *ppfn, const _PVFV* end) {
|
|
||||||
|
void CDECL _initterm(GUEST_PTR *ppfn, GUEST_PTR *end) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("_initterm(%p, %p)\n", ppfn, end);
|
DEBUG_LOG("_initterm(%p, %p)\n", ppfn, end);
|
||||||
for (; ppfn < end; ppfn++) {
|
do {
|
||||||
_PVFV func = *ppfn;
|
if (GUEST_PTR pfn = *++ppfn) {
|
||||||
if (func) {
|
DEBUG_LOG("-> calling %p\n", pfn);
|
||||||
DEBUG_LOG("_initterm: calling %p\n", func);
|
auto fn = reinterpret_cast<_PVFV>(fromGuestPtr(pfn));
|
||||||
call__PVFV(func);
|
call__PVFV(fn);
|
||||||
}
|
}
|
||||||
}
|
} while (ppfn < end);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end) {
|
int CDECL _initterm_e(GUEST_PTR *ppfn, GUEST_PTR *end) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("_initterm_e(%p, %p)\n", ppfn, end);
|
DEBUG_LOG("_initterm_e(%p, %p)\n", ppfn, end);
|
||||||
for (; ppfn < end; ppfn++) {
|
do {
|
||||||
_PIFV func = *ppfn;
|
if (GUEST_PTR pfn = *++ppfn) {
|
||||||
if (func) {
|
DEBUG_LOG("-> calling %p\n", pfn);
|
||||||
int err = call__PIFV(func);
|
auto fn = reinterpret_cast<_PIFV>(fromGuestPtr(pfn));
|
||||||
DEBUG_LOG("_initterm_e: calling %p -> %d\n", func, err);
|
int err = call__PIFV(fn);
|
||||||
if (err != 0)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
}
|
} while (ppfn < end);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -720,7 +723,7 @@ namespace msvcrt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(readability-non-const-parameter)
|
// NOLINTNEXTLINE(readability-non-const-parameter)
|
||||||
int CDECL __wgetmainargs(int *wargc, uint16_t ***wargv, uint16_t ***wenv, int doWildcard, int *startInfo) {
|
int CDECL __wgetmainargs(int *wargc, GUEST_PTR *wargv, GUEST_PTR *wenv, int doWildcard, int *startInfo) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("__wgetmainargs(doWildcard=%d)\n", doWildcard);
|
DEBUG_LOG("__wgetmainargs(doWildcard=%d)\n", doWildcard);
|
||||||
(void)startInfo;
|
(void)startInfo;
|
||||||
@@ -733,7 +736,7 @@ namespace msvcrt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOLINTNEXTLINE(readability-non-const-parameter)
|
// NOLINTNEXTLINE(readability-non-const-parameter)
|
||||||
int CDECL __getmainargs(int *argc, char ***argv, char ***env, int doWildcard, int *startInfo) {
|
int CDECL __getmainargs(int *argc, GUEST_PTR *argv, GUEST_PTR *env, int doWildcard, int *startInfo) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("__getmainargs(doWildcard=%d)\n", doWildcard);
|
DEBUG_LOG("__getmainargs(doWildcard=%d)\n", doWildcard);
|
||||||
(void)startInfo;
|
(void)startInfo;
|
||||||
@@ -749,10 +752,10 @@ namespace msvcrt {
|
|||||||
return std::getenv(varname);
|
return std::getenv(varname);
|
||||||
}
|
}
|
||||||
|
|
||||||
char*** CDECL __p___initenv() {
|
GUEST_PTR CDECL __p___initenv() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("__p___initenv() -> %p\n", &__initenv);
|
DEBUG_LOG("__p___initenv() -> %p\n", &__initenv);
|
||||||
return &__initenv;
|
return toGuestPtr(&__initenv);
|
||||||
}
|
}
|
||||||
|
|
||||||
char* CDECL strcat(char *dest, const char *src) {
|
char* CDECL strcat(char *dest, const char *src) {
|
||||||
@@ -881,7 +884,7 @@ namespace msvcrt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!prev) {
|
if (!prev) {
|
||||||
long diff = static_cast<long>(current - start);
|
LONG diff = static_cast<LONG>(current - start);
|
||||||
DEBUG_LOG("_mbsdec fallback start=%p current=%p diff=%ld first-bytes=%02x %02x %02x %02x\n",
|
DEBUG_LOG("_mbsdec fallback start=%p current=%p diff=%ld first-bytes=%02x %02x %02x %02x\n",
|
||||||
start, current, diff,
|
start, current, diff,
|
||||||
start ? start[0] : 0, start ? start[1] : 0,
|
start ? start[0] : 0, start ? start[1] : 0,
|
||||||
@@ -1166,11 +1169,11 @@ namespace msvcrt {
|
|||||||
return ::close(fd);
|
return ::close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
long CDECL _lseek(int fd, long offset, int origin) {
|
LONG CDECL _lseek(int fd, LONG offset, int origin) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("_lseek(%d, %ld, %d)\n", fd, offset, origin);
|
DEBUG_LOG("_lseek(%d, %ld, %d)\n", fd, offset, origin);
|
||||||
off_t result = ::lseek(fd, static_cast<off_t>(offset), origin);
|
off_t result = ::lseek(fd, static_cast<off_t>(offset), origin);
|
||||||
return static_cast<long>(result);
|
return static_cast<LONG>(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CDECL _unlink(const char *path) {
|
int CDECL _unlink(const char *path) {
|
||||||
@@ -1199,7 +1202,7 @@ namespace msvcrt {
|
|||||||
return ::utime(hostPath.c_str(), &native);
|
return ::utime(hostPath.c_str(), &native);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CDECL _chsize(int fd, long size) {
|
int CDECL _chsize(int fd, LONG size) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("_chsize(%d, %ld)\n", fd, size);
|
DEBUG_LOG("_chsize(%d, %ld)\n", fd, size);
|
||||||
return ::ftruncate(fd, static_cast<off_t>(size));
|
return ::ftruncate(fd, static_cast<off_t>(size));
|
||||||
@@ -1238,13 +1241,13 @@ namespace msvcrt {
|
|||||||
return std::strtok(str, delim);
|
return std::strtok(str, delim);
|
||||||
}
|
}
|
||||||
|
|
||||||
long CDECL _adj_fdiv_r(long value) {
|
LONG CDECL _adj_fdiv_r(LONG value) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("STUB: _adj_fdiv_r(%ld)\n", value);
|
DEBUG_LOG("STUB: _adj_fdiv_r(%ld)\n", value);
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CDECL _adjust_fdiv(long n) {
|
void CDECL _adjust_fdiv(LONG n) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("STUB: _adjust_fdiv(%ld)\n", n);
|
DEBUG_LOG("STUB: _adjust_fdiv(%ld)\n", n);
|
||||||
(void)n;
|
(void)n;
|
||||||
@@ -1261,14 +1264,14 @@ namespace msvcrt {
|
|||||||
if (gettimeofday(&tv, nullptr) != 0) {
|
if (gettimeofday(&tv, nullptr) != 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
timeptr->time = tv.tv_sec;
|
timeptr->time = static_cast<LONG>(tv.tv_sec);
|
||||||
timeptr->millitm = static_cast<unsigned short>(tv.tv_usec / 1000);
|
timeptr->millitm = static_cast<unsigned short>(tv.tv_usec / 1000);
|
||||||
timeptr->timezone = 0;
|
timeptr->timezone = 0;
|
||||||
timeptr->dstflag = 0;
|
timeptr->dstflag = 0;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long CDECL _ultoa(unsigned long value, char *str, int radix) {
|
ULONG CDECL _ultoa(ULONG value, char *str, int radix) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("_ultoa(%lu, %p, %d)\n", value, str, radix);
|
DEBUG_LOG("_ultoa(%lu, %p, %d)\n", value, str, radix);
|
||||||
if (!str || radix < 2 || radix > 36) {
|
if (!str || radix < 2 || radix > 36) {
|
||||||
@@ -1282,15 +1285,15 @@ namespace msvcrt {
|
|||||||
*--cursor = '0';
|
*--cursor = '0';
|
||||||
}
|
}
|
||||||
while (value > 0) {
|
while (value > 0) {
|
||||||
unsigned long digit = value % static_cast<unsigned long>(radix);
|
ULONG digit = value % static_cast<ULONG>(radix);
|
||||||
value /= static_cast<unsigned long>(radix);
|
value /= static_cast<ULONG>(radix);
|
||||||
*--cursor = static_cast<char>(digit < 10 ? '0' + digit : 'A' + (digit - 10));
|
*--cursor = static_cast<char>(digit < 10 ? '0' + digit : 'A' + (digit - 10));
|
||||||
}
|
}
|
||||||
std::strcpy(str, cursor);
|
std::strcpy(str, cursor);
|
||||||
return static_cast<unsigned long>(std::strlen(str));
|
return static_cast<ULONG>(std::strlen(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
char* CDECL _ltoa(long value, char *str, int radix) {
|
char* CDECL _ltoa(LONG value, char *str, int radix) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("_ltoa(%ld, %p, %d)\n", value, str, radix);
|
DEBUG_LOG("_ltoa(%ld, %p, %d)\n", value, str, radix);
|
||||||
if (!str || radix < 2 || radix > 36) {
|
if (!str || radix < 2 || radix > 36) {
|
||||||
@@ -1298,9 +1301,9 @@ namespace msvcrt {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
bool negative = value < 0;
|
bool negative = value < 0;
|
||||||
unsigned long absValue = negative ? static_cast<unsigned long>(-value) : static_cast<unsigned long>(value);
|
ULONG absValue = negative ? static_cast<ULONG>(-value) : static_cast<ULONG>(value);
|
||||||
char buffer[65];
|
char buffer[65];
|
||||||
unsigned long length = _ultoa(absValue, buffer, radix);
|
ULONG length = _ultoa(absValue, buffer, radix);
|
||||||
std::string result;
|
std::string result;
|
||||||
if (negative) {
|
if (negative) {
|
||||||
result.push_back('-');
|
result.push_back('-');
|
||||||
@@ -1437,7 +1440,7 @@ namespace msvcrt {
|
|||||||
TIME_T CDECL time(TIME_T *t) {
|
TIME_T CDECL time(TIME_T *t) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("time(%p)\n", t);
|
DEBUG_LOG("time(%p)\n", t);
|
||||||
TIME_T result = std::time(nullptr);
|
TIME_T result = static_cast<TIME_T>(std::time(nullptr));
|
||||||
if (t) {
|
if (t) {
|
||||||
*t = result;
|
*t = result;
|
||||||
}
|
}
|
||||||
@@ -1468,11 +1471,11 @@ namespace msvcrt {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CDECL _wdupenv_s(uint16_t **buffer, SIZE_T *numberOfElements, const uint16_t *varname){
|
int CDECL _wdupenv_s(GUEST_PTR *buffer, SIZE_T *numberOfElements, const uint16_t *varname){
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("_wdupenv_s(%p, %p, %s)\n", buffer, numberOfElements, wideStringToString(varname).c_str());
|
DEBUG_LOG("_wdupenv_s(%p, %p, %s)\n", buffer, numberOfElements, wideStringToString(varname).c_str());
|
||||||
if (buffer) {
|
if (buffer) {
|
||||||
*buffer = nullptr;
|
*buffer = GUEST_NULL;
|
||||||
}
|
}
|
||||||
if (numberOfElements) {
|
if (numberOfElements) {
|
||||||
*numberOfElements = 0;
|
*numberOfElements = 0;
|
||||||
@@ -1504,7 +1507,7 @@ namespace msvcrt {
|
|||||||
|
|
||||||
wstrncpy(copy, match->value, value_len);
|
wstrncpy(copy, match->value, value_len);
|
||||||
copy[value_len] = 0;
|
copy[value_len] = 0;
|
||||||
*buffer = copy;
|
*buffer = toGuestPtr(copy);
|
||||||
if (numberOfElements) {
|
if (numberOfElements) {
|
||||||
*numberOfElements = value_len + 1;
|
*numberOfElements = value_len + 1;
|
||||||
}
|
}
|
||||||
@@ -1678,10 +1681,18 @@ namespace msvcrt {
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long CDECL strtoul(const char *str, char **endptr, int base) {
|
ULONG CDECL strtoul(const char *str, GUEST_PTR *endptr, int base) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("strtoul(%s, %p, %d)\n", str, endptr, base);
|
VERBOSE_LOG("strtoul(%s, %p, %d)\n", str, endptr, base);
|
||||||
return ::strtoul(str, endptr, base);
|
int ret;
|
||||||
|
if (endptr != nullptr) {
|
||||||
|
char *endptr_host = reinterpret_cast<char*>(fromGuestPtr(*endptr));
|
||||||
|
ret = ::strtoul(str, &endptr_host, base);
|
||||||
|
*endptr = toGuestPtr(endptr_host);
|
||||||
|
} else {
|
||||||
|
ret = ::strtoul(str, nullptr, base);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* CDECL malloc(SIZE_T size){
|
void* CDECL malloc(SIZE_T size){
|
||||||
@@ -1728,7 +1739,7 @@ namespace msvcrt {
|
|||||||
lockTable()[static_cast<SIZE_T>(locknum)].unlock();
|
lockTable()[static_cast<SIZE_T>(locknum)].unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
_onexit_t CDECL __dllonexit(_onexit_t func, _onexit_t **pbegin, _onexit_t **pend) {
|
_onexit_t CDECL __dllonexit(_onexit_t func, GUEST_PTR *pbegin, GUEST_PTR *pend) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("__dllonexit(%p, %p, %p)\n", func, pbegin, pend);
|
DEBUG_LOG("__dllonexit(%p, %p, %p)\n", func, pbegin, pend);
|
||||||
if (!pbegin || !pend) {
|
if (!pbegin || !pend) {
|
||||||
@@ -1740,13 +1751,13 @@ namespace msvcrt {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
_onexit_t *table = static_cast<_onexit_t *>(wibo::heap::guestRealloc(pbegin, len * sizeof(_onexit_t)));
|
GUEST_PTR *table = static_cast<GUEST_PTR *>(wibo::heap::guestRealloc(pbegin, len * sizeof(GUEST_PTR)));
|
||||||
if (!table) {
|
if (!table) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
*pbegin = table;
|
*pbegin = toGuestPtr(table);
|
||||||
*pend = table + len;
|
*pend = toGuestPtr(table + len);
|
||||||
table[len - 1] = func;
|
table[len - 1] = toGuestPtr(reinterpret_cast<void *>(func));
|
||||||
return func;
|
return func;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1827,14 +1838,14 @@ namespace msvcrt {
|
|||||||
return isatty(fd);
|
return isatty(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CDECL fseek(_FILE *stream, long offset, int origin) {
|
int CDECL fseek(_FILE *stream, LONG offset, int origin) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("fseek(%p, %ld, %d)\n", stream, offset, origin);
|
VERBOSE_LOG("fseek(%p, %ld, %d)\n", stream, offset, origin);
|
||||||
FILE* host = mapToHostFile(stream);
|
FILE* host = mapToHostFile(stream);
|
||||||
return std::fseek(host, offset, origin);
|
return std::fseek(host, offset, origin);
|
||||||
}
|
}
|
||||||
|
|
||||||
long CDECL ftell(_FILE *stream) {
|
LONG CDECL ftell(_FILE *stream) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("ftell(%p)\n", stream);
|
VERBOSE_LOG("ftell(%p)\n", stream);
|
||||||
FILE* host = mapToHostFile(stream);
|
FILE* host = mapToHostFile(stream);
|
||||||
@@ -1895,7 +1906,7 @@ namespace msvcrt {
|
|||||||
return std::fgetwc(host);
|
return std::fgetwc(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CDECL _wfopen_s(_FILE **stream, const uint16_t *filename, const uint16_t *mode) {
|
int CDECL _wfopen_s(GUEST_PTR *stream, const uint16_t *filename, const uint16_t *mode) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("_wfopen_s(%p, %s, %s)\n", stream, wideStringToString(filename).c_str(),
|
DEBUG_LOG("_wfopen_s(%p, %s, %s)\n", stream, wideStringToString(filename).c_str(),
|
||||||
wideStringToString(mode).c_str());
|
wideStringToString(mode).c_str());
|
||||||
@@ -1907,10 +1918,10 @@ namespace msvcrt {
|
|||||||
std::string narrowMode = wideStringToString(mode);
|
std::string narrowMode = wideStringToString(mode);
|
||||||
FILE *handle = std::fopen(narrowName.c_str(), narrowMode.c_str());
|
FILE *handle = std::fopen(narrowName.c_str(), narrowMode.c_str());
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
*stream = nullptr;
|
*stream = GUEST_NULL;
|
||||||
return errno ? errno : EINVAL;
|
return errno ? errno : EINVAL;
|
||||||
}
|
}
|
||||||
*stream = mapToGuestFile(handle);
|
*stream = toGuestPtr(mapToGuestFile(handle));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2061,13 +2072,13 @@ namespace msvcrt {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long CDECL wcsspn(const uint16_t *str1, const uint16_t *str2) {
|
ULONG CDECL wcsspn(const uint16_t *str1, const uint16_t *str2) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("wcsspn(%p, %p)\n", str1, str2);
|
VERBOSE_LOG("wcsspn(%p, %p)\n", str1, str2);
|
||||||
if (!str1 || !str2) {
|
if (!str1 || !str2) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
unsigned long count = 0;
|
ULONG count = 0;
|
||||||
for (const uint16_t *p = str1; *p; ++p) {
|
for (const uint16_t *p = str1; *p; ++p) {
|
||||||
bool match = false;
|
bool match = false;
|
||||||
for (const uint16_t *q = str2; *q; ++q) {
|
for (const uint16_t *q = str2; *q; ++q) {
|
||||||
@@ -2084,7 +2095,7 @@ namespace msvcrt {
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
long CDECL _wtol(const uint16_t *str) {
|
LONG CDECL _wtol(const uint16_t *str) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("_wtol(%p)\n", str);
|
VERBOSE_LOG("_wtol(%p)\n", str);
|
||||||
return wstrtol(str, nullptr, 10);
|
return wstrtol(str, nullptr, 10);
|
||||||
@@ -2341,13 +2352,13 @@ namespace msvcrt {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
long CDECL _XcptFilter(unsigned long code, void *) {
|
LONG CDECL _XcptFilter(ULONG code, void *) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("STUB: _XcptFilter(%lu)\n", code);
|
DEBUG_LOG("STUB: _XcptFilter(%lu)\n", code);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CDECL _get_wpgmptr(uint16_t **pValue) {
|
int CDECL _get_wpgmptr(GUEST_PTR *pValue) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("_get_wpgmptr(%p)\n", pValue);
|
DEBUG_LOG("_get_wpgmptr(%p)\n", pValue);
|
||||||
if (!pValue) {
|
if (!pValue) {
|
||||||
@@ -2358,22 +2369,25 @@ namespace msvcrt {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto wStr = stringToWideString(wibo::guestExecutablePath.c_str());
|
// TODO
|
||||||
delete[] _wpgmptr;
|
// const auto wStr = stringToWideString(wibo::guestExecutablePath.c_str());
|
||||||
|
// delete[] _wpgmptr;
|
||||||
|
|
||||||
_wpgmptr = new uint16_t[wStr.size() + 1];
|
// _wpgmptr = new uint16_t[wStr.size() + 1];
|
||||||
std::copy(wStr.begin(), wStr.end(), _wpgmptr);
|
// std::copy(wStr.begin(), wStr.end(), _wpgmptr);
|
||||||
_wpgmptr[wStr.size()] = 0;
|
// _wpgmptr[wStr.size()] = 0;
|
||||||
|
|
||||||
*pValue = _wpgmptr;
|
// *pValue = _wpgmptr;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char** CDECL __p__pgmptr() {
|
GUEST_PTR CDECL __p__pgmptr() {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("__p__pgmptr()\n");
|
DEBUG_LOG("__p__pgmptr()\n");
|
||||||
_pgmptr = const_cast<char *>(wibo::guestExecutablePath.c_str());
|
// TODO
|
||||||
return &_pgmptr;
|
// _pgmptr = const_cast<char *>(wibo::guestExecutablePath.c_str());
|
||||||
|
// return &_pgmptr;
|
||||||
|
return GUEST_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int CDECL _wsplitpath_s(const uint16_t * path, uint16_t * drive, SIZE_T driveNumberOfElements, uint16_t *dir, SIZE_T dirNumberOfElements,
|
int CDECL _wsplitpath_s(const uint16_t * path, uint16_t * drive, SIZE_T driveNumberOfElements, uint16_t *dir, SIZE_T dirNumberOfElements,
|
||||||
@@ -2564,7 +2578,7 @@ namespace msvcrt {
|
|||||||
return wstrtol(str, nullptr, 10);
|
return wstrtol(str, nullptr, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
int CDECL _ltoa_s(long value, char *buffer, SIZE_T sizeInChars, int radix) {
|
int CDECL _ltoa_s(LONG value, char *buffer, SIZE_T sizeInChars, int radix) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("_ltoa_s(%ld, %p, %zu, %d)\n", value, buffer, sizeInChars, radix);
|
VERBOSE_LOG("_ltoa_s(%ld, %p, %zu, %d)\n", value, buffer, sizeInChars, radix);
|
||||||
if (!buffer || sizeInChars == 0) {
|
if (!buffer || sizeInChars == 0) {
|
||||||
@@ -2782,10 +2796,18 @@ namespace msvcrt {
|
|||||||
return wstrrchr(str, c);
|
return wstrrchr(str, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long CDECL wcstoul(const uint16_t *strSource, uint16_t **endptr, int base){
|
ULONG CDECL wcstoul(const uint16_t *strSource, GUEST_PTR *endptr, int base){
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
VERBOSE_LOG("wcstoul(%p, %p, %d)\n", strSource, endptr, base);
|
VERBOSE_LOG("wcstoul(%p, %p, %d)\n", strSource, endptr, base);
|
||||||
return wstrtoul(strSource, endptr, base);
|
int ret;
|
||||||
|
if (endptr != nullptr) {
|
||||||
|
uint16_t *endptr_host = reinterpret_cast<uint16_t*>(fromGuestPtr(*endptr));
|
||||||
|
ret = ::wstrtoul(strSource, &endptr_host, base);
|
||||||
|
*endptr = toGuestPtr(endptr_host);
|
||||||
|
} else {
|
||||||
|
ret = ::wstrtoul(strSource, nullptr, base);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
_FILE* CDECL _wfsopen(const uint16_t* filename, const uint16_t* mode, int shflag){
|
_FILE* CDECL _wfsopen(const uint16_t* filename, const uint16_t* mode, int shflag){
|
||||||
@@ -2842,7 +2864,7 @@ namespace msvcrt {
|
|||||||
return &errno;
|
return &errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
LONG_PTR CDECL _wspawnvp(int mode, const uint16_t* cmdname, const uint16_t* const * argv) {
|
LONG_PTR CDECL _wspawnvp(int mode, const uint16_t* cmdname, GUEST_PTR *argv) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
if (!cmdname || !argv) {
|
if (!cmdname || !argv) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
@@ -2853,8 +2875,9 @@ namespace msvcrt {
|
|||||||
DEBUG_LOG("_wspawnvp(%d, %s)\n", mode, command.c_str());
|
DEBUG_LOG("_wspawnvp(%d, %s)\n", mode, command.c_str());
|
||||||
|
|
||||||
std::vector<std::string> argStorage;
|
std::vector<std::string> argStorage;
|
||||||
for (const uint16_t *const *cursor = argv; *cursor; ++cursor) {
|
for (GUEST_PTR *cursor = argv; *cursor; ++cursor) {
|
||||||
argStorage.emplace_back(wideStringToString(*cursor));
|
const WCHAR *arg = reinterpret_cast<const WCHAR*>(fromGuestPtr(*cursor));
|
||||||
|
argStorage.emplace_back(wideStringToString(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto resolved = wibo::resolveExecutable(command, false);
|
auto resolved = wibo::resolveExecutable(command, false);
|
||||||
@@ -2891,7 +2914,7 @@ namespace msvcrt {
|
|||||||
return static_cast<intptr_t>(po->pid);
|
return static_cast<intptr_t>(po->pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
LONG_PTR CDECL _spawnvp(int mode, const char *cmdname, const char * const *argv) {
|
LONG_PTR CDECL _spawnvp(int mode, const char *cmdname, GUEST_PTR *argv) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
if (!cmdname || !argv) {
|
if (!cmdname || !argv) {
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
@@ -2902,8 +2925,9 @@ namespace msvcrt {
|
|||||||
DEBUG_LOG("_spawnvp(%d, %s)\n", mode, command.c_str());
|
DEBUG_LOG("_spawnvp(%d, %s)\n", mode, command.c_str());
|
||||||
|
|
||||||
std::vector<std::string> argStorage;
|
std::vector<std::string> argStorage;
|
||||||
for (const char * const *cursor = argv; *cursor; ++cursor) {
|
for (GUEST_PTR *cursor = argv; *cursor; ++cursor) {
|
||||||
argStorage.emplace_back(*cursor);
|
const char *arg = reinterpret_cast<const char*>(fromGuestPtr(*cursor));
|
||||||
|
argStorage.emplace_back(arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto resolved = wibo::resolveExecutable(command, false);
|
auto resolved = wibo::resolveExecutable(command, false);
|
||||||
|
|||||||
84
dll/msvcrt.h
84
dll/msvcrt.h
@@ -12,8 +12,8 @@ typedef void(_CC_CDECL *signal_handler)(int);
|
|||||||
typedef int(_CC_CDECL *sort_compare)(const void *, const void *);
|
typedef int(_CC_CDECL *sort_compare)(const void *, const void *);
|
||||||
|
|
||||||
struct _utimbuf {
|
struct _utimbuf {
|
||||||
long actime;
|
LONG actime;
|
||||||
long modtime;
|
LONG modtime;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct _timeb {
|
struct _timeb {
|
||||||
@@ -29,10 +29,10 @@ namespace msvcrt {
|
|||||||
|
|
||||||
extern int _commode;
|
extern int _commode;
|
||||||
extern int _fmode;
|
extern int _fmode;
|
||||||
extern char **__initenv;
|
extern GUEST_PTR __initenv;
|
||||||
extern WCHAR **__winitenv;
|
extern GUEST_PTR __winitenv;
|
||||||
extern WCHAR *_wpgmptr;
|
extern GUEST_PTR _wpgmptr;
|
||||||
extern char *_pgmptr;
|
extern GUEST_PTR _pgmptr;
|
||||||
extern int __mb_cur_max;
|
extern int __mb_cur_max;
|
||||||
extern _FILE _iob[_IOB_ENTRIES];
|
extern _FILE _iob[_IOB_ENTRIES];
|
||||||
|
|
||||||
@@ -42,23 +42,23 @@ void CDECL setbuf(_FILE *stream, char *buffer);
|
|||||||
void CDECL _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext);
|
void CDECL _splitpath(const char *path, char *drive, char *dir, char *fname, char *ext);
|
||||||
int CDECL _fileno(_FILE *stream);
|
int CDECL _fileno(_FILE *stream);
|
||||||
int CDECL _getmbcp();
|
int CDECL _getmbcp();
|
||||||
int *CDECL __p___mb_cur_max();
|
GUEST_PTR CDECL __p___mb_cur_max();
|
||||||
int CDECL _setmbcp(int codepage);
|
int CDECL _setmbcp(int codepage);
|
||||||
unsigned char *CDECL __p__mbctype();
|
GUEST_PTR CDECL __p__mbctype();
|
||||||
unsigned short **CDECL __p__pctype();
|
GUEST_PTR CDECL __p__pctype();
|
||||||
int CDECL _isctype(int ch, int mask);
|
int CDECL _isctype(int ch, int mask);
|
||||||
void CDECL __set_app_type(int at);
|
void CDECL __set_app_type(int at);
|
||||||
int *CDECL __p__fmode();
|
GUEST_PTR CDECL __p__fmode();
|
||||||
int *CDECL __p__commode();
|
GUEST_PTR CDECL __p__commode();
|
||||||
void CDECL _initterm(const _PVFV *ppfn, const _PVFV *end);
|
void CDECL _initterm(GUEST_PTR *ppfn, GUEST_PTR *end);
|
||||||
int CDECL _initterm_e(const _PIFV *ppfn, const _PIFV *end);
|
int CDECL _initterm_e(GUEST_PTR *ppfn, GUEST_PTR *end);
|
||||||
unsigned int CDECL _controlfp(unsigned int newControl, unsigned int mask);
|
unsigned int CDECL _controlfp(unsigned int newControl, unsigned int mask);
|
||||||
int CDECL _controlfp_s(unsigned int *currentControl, 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);
|
_onexit_t CDECL _onexit(_onexit_t func);
|
||||||
int CDECL __wgetmainargs(int *wargc, WCHAR ***wargv, WCHAR ***wenv, int doWildcard, int *startInfo);
|
int CDECL __wgetmainargs(int *wargc, GUEST_PTR *wargv, GUEST_PTR *wenv, int doWildcard, int *startInfo);
|
||||||
int CDECL __getmainargs(int *argc, char ***argv, char ***env, 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);
|
char *CDECL getenv(const char *varname);
|
||||||
char ***CDECL __p___initenv();
|
GUEST_PTR CDECL __p___initenv();
|
||||||
char *CDECL strcat(char *dest, const char *src);
|
char *CDECL strcat(char *dest, const char *src);
|
||||||
char *CDECL strcpy(char *dest, const char *src);
|
char *CDECL strcpy(char *dest, const char *src);
|
||||||
int CDECL _access(const char *path, int mode);
|
int CDECL _access(const char *path, int mode);
|
||||||
@@ -84,31 +84,33 @@ int CDECL _ismbcdigit(unsigned int ch);
|
|||||||
int CDECL _stricmp(const char *lhs, const char *rhs);
|
int CDECL _stricmp(const char *lhs, const char *rhs);
|
||||||
int CDECL _strnicmp(const char *lhs, const char *rhs, SIZE_T count);
|
int CDECL _strnicmp(const char *lhs, const char *rhs, SIZE_T count);
|
||||||
int CDECL _memicmp(const void *lhs, const void *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 _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 _snprintf(char *buffer, SIZE_T count, const char *format, ...);
|
||||||
int CDECL_NO_CONV sprintf(char *buffer, 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 printf(const char *format, ...);
|
||||||
int CDECL_NO_CONV sscanf(const char *buffer, const char *format, ...);
|
int CDECL_NO_CONV sscanf(const char *buffer, const char *format, ...);
|
||||||
|
#endif
|
||||||
char *CDECL fgets(char *str, int count, _FILE *stream);
|
char *CDECL fgets(char *str, int count, _FILE *stream);
|
||||||
SIZE_T CDECL fread(void *buffer, SIZE_T size, SIZE_T 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);
|
_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 _sopen(const char *path, int oflag, int shflag, int pmode);
|
||||||
int CDECL _read(int fd, void *buffer, unsigned int count);
|
int CDECL _read(int fd, void *buffer, unsigned int count);
|
||||||
int CDECL _close(int fd);
|
int CDECL _close(int fd);
|
||||||
long CDECL _lseek(int fd, long offset, int origin);
|
LONG CDECL _lseek(int fd, LONG offset, int origin);
|
||||||
int CDECL _unlink(const char *path);
|
int CDECL _unlink(const char *path);
|
||||||
int CDECL _utime(const char *path, const _utimbuf *times);
|
int CDECL _utime(const char *path, const _utimbuf *times);
|
||||||
int CDECL _chsize(int fd, long size);
|
int CDECL _chsize(int fd, LONG size);
|
||||||
char *CDECL strncpy(char *dest, const char *src, SIZE_T count);
|
char *CDECL strncpy(char *dest, const char *src, SIZE_T count);
|
||||||
char *CDECL strpbrk(const char *str, const char *accept);
|
char *CDECL strpbrk(const char *str, const char *accept);
|
||||||
char *CDECL strstr(const char *haystack, const char *needle);
|
char *CDECL strstr(const char *haystack, const char *needle);
|
||||||
char *CDECL strrchr(const char *str, int ch);
|
char *CDECL strrchr(const char *str, int ch);
|
||||||
char *CDECL strtok(char *str, const char *delim);
|
char *CDECL strtok(char *str, const char *delim);
|
||||||
long CDECL _adj_fdiv_r(long value);
|
LONG CDECL _adj_fdiv_r(LONG value);
|
||||||
void CDECL _adjust_fdiv(long n);
|
void CDECL _adjust_fdiv(LONG n);
|
||||||
int CDECL _ftime(struct _timeb *timeptr);
|
int CDECL _ftime(struct _timeb *timeptr);
|
||||||
unsigned long CDECL _ultoa(unsigned long value, char *str, int radix);
|
ULONG CDECL _ultoa(ULONG value, char *str, int radix);
|
||||||
char *CDECL _ltoa(long 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 _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);
|
char *CDECL _fullpath(char *absPath, const char *relPath, SIZE_T maxLength);
|
||||||
int CDECL _putenv(const char *envString);
|
int CDECL _putenv(const char *envString);
|
||||||
@@ -119,7 +121,7 @@ TIME_T CDECL time(TIME_T *t);
|
|||||||
char *CDECL __unDName(char *outputString, const char *mangledName, int maxStringLength, void *(*allocFunc)(SIZE_T),
|
char *CDECL __unDName(char *outputString, const char *mangledName, int maxStringLength, void *(*allocFunc)(SIZE_T),
|
||||||
void (*freeFunc)(void *), unsigned short);
|
void (*freeFunc)(void *), unsigned short);
|
||||||
char *CDECL setlocale(int category, const char *locale);
|
char *CDECL setlocale(int category, const char *locale);
|
||||||
int CDECL _wdupenv_s(WCHAR **buffer, SIZE_T *numberOfElements, const WCHAR *varname);
|
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);
|
int CDECL _wgetenv_s(SIZE_T *pReturnValue, WCHAR *buffer, SIZE_T numberOfElements, const WCHAR *varname);
|
||||||
SIZE_T CDECL strlen(const char *str);
|
SIZE_T CDECL strlen(const char *str);
|
||||||
int CDECL strcmp(const char *lhs, const char *rhs);
|
int CDECL strcmp(const char *lhs, const char *rhs);
|
||||||
@@ -129,38 +131,40 @@ 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 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);
|
int CDECL strncpy_s(char *dest, SIZE_T dest_size, const char *src, SIZE_T count);
|
||||||
char *CDECL _strdup(const char *strSource);
|
char *CDECL _strdup(const char *strSource);
|
||||||
unsigned long CDECL strtoul(const char *str, char **endptr, int base);
|
ULONG CDECL strtoul(const char *str, GUEST_PTR *endptr, int base);
|
||||||
void *CDECL malloc(SIZE_T size);
|
void *CDECL malloc(SIZE_T size);
|
||||||
void *CDECL calloc(SIZE_T count, SIZE_T size);
|
void *CDECL calloc(SIZE_T count, SIZE_T size);
|
||||||
void *CDECL realloc(void *ptr, SIZE_T size);
|
void *CDECL realloc(void *ptr, SIZE_T size);
|
||||||
void *CDECL _malloc_crt(SIZE_T size);
|
void *CDECL _malloc_crt(SIZE_T size);
|
||||||
void CDECL _lock(int locknum);
|
void CDECL _lock(int locknum);
|
||||||
void CDECL _unlock(int locknum);
|
void CDECL _unlock(int locknum);
|
||||||
_onexit_t CDECL __dllonexit(_onexit_t func, _onexit_t **pbegin, _onexit_t **pend);
|
_onexit_t CDECL __dllonexit(_onexit_t func, GUEST_PTR *pbegin, GUEST_PTR *pend);
|
||||||
void CDECL free(void *ptr);
|
void CDECL free(void *ptr);
|
||||||
void *CDECL memcpy(void *dest, const void *src, SIZE_T count);
|
void *CDECL memcpy(void *dest, const void *src, SIZE_T count);
|
||||||
void *CDECL memmove(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);
|
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);
|
void CDECL qsort(void *base, SIZE_T num, SIZE_T size, sort_compare compare);
|
||||||
int CDECL fflush(_FILE *stream);
|
int CDECL fflush(_FILE *stream);
|
||||||
|
#ifndef __x86_64__ // TODO
|
||||||
int CDECL_NO_CONV vfwprintf(_FILE *stream, const WCHAR *format, va_list args);
|
int CDECL_NO_CONV vfwprintf(_FILE *stream, const WCHAR *format, va_list args);
|
||||||
|
#endif
|
||||||
_FILE *CDECL fopen(const char *filename, const char *mode);
|
_FILE *CDECL fopen(const char *filename, const char *mode);
|
||||||
int CDECL _dup2(int fd1, int fd2);
|
int CDECL _dup2(int fd1, int fd2);
|
||||||
int CDECL _isatty(int fd);
|
int CDECL _isatty(int fd);
|
||||||
int CDECL fseek(_FILE *stream, long offset, int origin);
|
int CDECL fseek(_FILE *stream, LONG offset, int origin);
|
||||||
long CDECL ftell(_FILE *stream);
|
LONG CDECL ftell(_FILE *stream);
|
||||||
int CDECL feof(_FILE *stream);
|
int CDECL feof(_FILE *stream);
|
||||||
int CDECL fputws(const WCHAR *str, _FILE *stream);
|
int CDECL fputws(const WCHAR *str, _FILE *stream);
|
||||||
int CDECL _cputws(const WCHAR *string);
|
int CDECL _cputws(const WCHAR *string);
|
||||||
WCHAR *CDECL fgetws(WCHAR *buffer, int size, _FILE *stream);
|
WCHAR *CDECL fgetws(WCHAR *buffer, int size, _FILE *stream);
|
||||||
WINT_T CDECL fgetwc(_FILE *stream);
|
WINT_T CDECL fgetwc(_FILE *stream);
|
||||||
int CDECL _wfopen_s(_FILE **stream, const WCHAR *filename, const WCHAR *mode);
|
int CDECL _wfopen_s(GUEST_PTR *stream, const WCHAR *filename, const WCHAR *mode);
|
||||||
int CDECL _wcsicmp(const WCHAR *lhs, const WCHAR *rhs);
|
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,
|
int CDECL _wmakepath_s(WCHAR *path, SIZE_T sizeInWords, const WCHAR *drive, const WCHAR *dir, const WCHAR *fname,
|
||||||
const WCHAR *ext);
|
const WCHAR *ext);
|
||||||
int CDECL _wputenv_s(const WCHAR *varname, const WCHAR *value);
|
int CDECL _wputenv_s(const WCHAR *varname, const WCHAR *value);
|
||||||
unsigned long CDECL wcsspn(const WCHAR *str1, const WCHAR *str2);
|
ULONG CDECL wcsspn(const WCHAR *str1, const WCHAR *str2);
|
||||||
long CDECL _wtol(const WCHAR *str);
|
LONG CDECL _wtol(const WCHAR *str);
|
||||||
int CDECL _wcsupr_s(WCHAR *str, SIZE_T size);
|
int CDECL _wcsupr_s(WCHAR *str, SIZE_T size);
|
||||||
int CDECL _wcslwr_s(WCHAR *str, SIZE_T size);
|
int CDECL _wcslwr_s(WCHAR *str, SIZE_T size);
|
||||||
WINT_T CDECL towlower(WINT_T ch);
|
WINT_T CDECL towlower(WINT_T ch);
|
||||||
@@ -172,8 +176,10 @@ int CDECL _crt_debugger_hook(int value);
|
|||||||
int CDECL _configthreadlocale(int mode);
|
int CDECL _configthreadlocale(int mode);
|
||||||
void CDECL __setusermatherr(void *handler);
|
void CDECL __setusermatherr(void *handler);
|
||||||
void CDECL _cexit();
|
void CDECL _cexit();
|
||||||
|
#ifndef __x86_64__ // TODO
|
||||||
int CDECL_NO_CONV vfprintf(_FILE *stream, const char *format, va_list args);
|
int CDECL_NO_CONV vfprintf(_FILE *stream, const char *format, va_list args);
|
||||||
int CDECL_NO_CONV fprintf(_FILE *stream, const char *format, ...);
|
int CDECL_NO_CONV fprintf(_FILE *stream, const char *format, ...);
|
||||||
|
#endif
|
||||||
int CDECL fputc(int ch, _FILE *stream);
|
int CDECL fputc(int ch, _FILE *stream);
|
||||||
SIZE_T CDECL fwrite(const void *buffer, SIZE_T size, SIZE_T count, _FILE *stream);
|
SIZE_T CDECL fwrite(const void *buffer, SIZE_T size, SIZE_T count, _FILE *stream);
|
||||||
char *CDECL strerror(int errnum);
|
char *CDECL strerror(int errnum);
|
||||||
@@ -188,9 +194,9 @@ void CDECL _invoke_watson(const WCHAR *, const WCHAR *, const WCHAR *, UINT, UIN
|
|||||||
void CDECL terminateShim();
|
void CDECL terminateShim();
|
||||||
int CDECL _purecall();
|
int CDECL _purecall();
|
||||||
int CDECL _except_handler4_common(void *, void *, void *, void *);
|
int CDECL _except_handler4_common(void *, void *, void *, void *);
|
||||||
long CDECL _XcptFilter(unsigned long code, void *);
|
LONG CDECL _XcptFilter(ULONG code, void *);
|
||||||
int CDECL _get_wpgmptr(WCHAR **pValue);
|
int CDECL _get_wpgmptr(GUEST_PTR *pValue);
|
||||||
char **CDECL __p__pgmptr();
|
GUEST_PTR CDECL __p__pgmptr();
|
||||||
int CDECL _wsplitpath_s(const WCHAR *path, WCHAR *drive, SIZE_T driveNumberOfElements, WCHAR *dir,
|
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 dirNumberOfElements, WCHAR *fname, SIZE_T nameNumberOfElements, WCHAR *ext,
|
||||||
SIZE_T extNumberOfElements);
|
SIZE_T extNumberOfElements);
|
||||||
@@ -202,28 +208,32 @@ int CDECL wcsncpy_s(WCHAR *strDest, SIZE_T numberOfElements, const WCHAR *strSou
|
|||||||
int CDECL wcsncat_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 _itow_s(int value, WCHAR *buffer, SIZE_T size, int radix);
|
||||||
int CDECL _wtoi(const WCHAR *str);
|
int CDECL _wtoi(const WCHAR *str);
|
||||||
int CDECL _ltoa_s(long value, char *buffer, SIZE_T sizeInChars, int radix);
|
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);
|
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 swprintf_s(WCHAR *buffer, SIZE_T sizeOfBuffer, const WCHAR *format, ...);
|
||||||
int CDECL_NO_CONV swscanf_s(const WCHAR *buffer, const WCHAR *format, ...);
|
int CDECL_NO_CONV swscanf_s(const WCHAR *buffer, const WCHAR *format, ...);
|
||||||
|
#endif
|
||||||
int *CDECL _get_osfhandle(int fd);
|
int *CDECL _get_osfhandle(int fd);
|
||||||
int CDECL _write(int fd, const void *buffer, unsigned int count);
|
int CDECL _write(int fd, const void *buffer, unsigned int count);
|
||||||
void CDECL exit(int status);
|
void CDECL exit(int status);
|
||||||
int CDECL wcsncmp(const WCHAR *string1, const WCHAR *string2, SIZE_T count);
|
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, ...);
|
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);
|
const WCHAR *CDECL wcsstr(const WCHAR *dest, const WCHAR *src);
|
||||||
int CDECL iswspace(WINT_T w);
|
int CDECL iswspace(WINT_T w);
|
||||||
int CDECL iswdigit(WINT_T w);
|
int CDECL iswdigit(WINT_T w);
|
||||||
const WCHAR *CDECL wcschr(const WCHAR *str, WCHAR c);
|
const WCHAR *CDECL wcschr(const WCHAR *str, WCHAR c);
|
||||||
const WCHAR *CDECL wcsrchr(const WCHAR *str, WCHAR c);
|
const WCHAR *CDECL wcsrchr(const WCHAR *str, WCHAR c);
|
||||||
unsigned long CDECL wcstoul(const WCHAR *strSource, WCHAR **endptr, int base);
|
ULONG CDECL wcstoul(const WCHAR *strSource, GUEST_PTR *endptr, int base);
|
||||||
_FILE *CDECL _wfsopen(const WCHAR *filename, const WCHAR *mode, int shflag);
|
_FILE *CDECL _wfsopen(const WCHAR *filename, const WCHAR *mode, int shflag);
|
||||||
int CDECL puts(const char *str);
|
int CDECL puts(const char *str);
|
||||||
int CDECL fclose(_FILE *stream);
|
int CDECL fclose(_FILE *stream);
|
||||||
int CDECL _flushall();
|
int CDECL _flushall();
|
||||||
int *CDECL _errno();
|
int *CDECL _errno();
|
||||||
LONG_PTR CDECL _wspawnvp(int mode, const WCHAR *cmdname, const WCHAR *const *argv);
|
LONG_PTR CDECL _wspawnvp(int mode, const WCHAR *cmdname, GUEST_PTR *argv);
|
||||||
LONG_PTR CDECL _spawnvp(int mode, const char *cmdname, const char *const *argv);
|
LONG_PTR CDECL _spawnvp(int mode, const char *cmdname, GUEST_PTR *argv);
|
||||||
int CDECL _wunlink(const WCHAR *filename);
|
int CDECL _wunlink(const WCHAR *filename);
|
||||||
WCHAR *CDECL _wfullpath(WCHAR *absPath, const WCHAR *relPath, SIZE_T maxLength);
|
WCHAR *CDECL _wfullpath(WCHAR *absPath, const WCHAR *relPath, SIZE_T maxLength);
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ namespace {
|
|||||||
|
|
||||||
struct PROCESS_BASIC_INFORMATION {
|
struct PROCESS_BASIC_INFORMATION {
|
||||||
NTSTATUS ExitStatus;
|
NTSTATUS ExitStatus;
|
||||||
PEB *PebBaseAddress;
|
GUEST_PTR PebBaseAddress;
|
||||||
ULONG_PTR AffinityMask;
|
ULONG_PTR AffinityMask;
|
||||||
LONG BasePriority;
|
LONG BasePriority;
|
||||||
ULONG_PTR UniqueProcessId;
|
ULONG_PTR UniqueProcessId;
|
||||||
@@ -94,8 +94,8 @@ std::string windowsImagePathFor(const ProcessHandleDetails &details) {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace kernel32 {
|
namespace kernel32 {
|
||||||
BOOL WIN_FUNC SetEvent(HANDLE hEvent);
|
BOOL WINAPI SetEvent(HANDLE hEvent);
|
||||||
BOOL WIN_FUNC ResetEvent(HANDLE hEvent);
|
BOOL WINAPI ResetEvent(HANDLE hEvent);
|
||||||
} // namespace kernel32
|
} // namespace kernel32
|
||||||
|
|
||||||
namespace ntdll {
|
namespace ntdll {
|
||||||
@@ -262,7 +262,7 @@ NTSTATUS WINAPI NtWriteFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE Apc
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits,
|
NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, GUEST_PTR *BaseAddress, ULONG_PTR ZeroBits,
|
||||||
PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect) {
|
PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("NtAllocateVirtualMemory(%p, %p, %lu, %p, %lu, %lu) ", ProcessHandle, BaseAddress, ZeroBits, RegionSize,
|
DEBUG_LOG("NtAllocateVirtualMemory(%p, %p, %lu, %p, %lu, %lu) ", ProcessHandle, BaseAddress, ZeroBits, RegionSize,
|
||||||
@@ -276,20 +276,24 @@ NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress
|
|||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
wibo::heap::VmStatus vmStatus =
|
void *baseAddress = fromGuestPtr(*BaseAddress);
|
||||||
wibo::heap::virtualAlloc(reinterpret_cast<void **>(BaseAddress), reinterpret_cast<std::size_t *>(RegionSize),
|
size_t regionSize = static_cast<size_t>(*RegionSize);
|
||||||
static_cast<DWORD>(AllocationType), static_cast<DWORD>(Protect));
|
wibo::heap::VmStatus vmStatus = wibo::heap::virtualAlloc(
|
||||||
|
&baseAddress, ®ionSize, static_cast<DWORD>(AllocationType), static_cast<DWORD>(Protect));
|
||||||
if (vmStatus != wibo::heap::VmStatus::Success) {
|
if (vmStatus != wibo::heap::VmStatus::Success) {
|
||||||
NTSTATUS status = wibo::heap::ntStatusFromVmStatus(vmStatus);
|
NTSTATUS status = wibo::heap::ntStatusFromVmStatus(vmStatus);
|
||||||
DEBUG_LOG("-> 0x%x\n", status);
|
DEBUG_LOG("-> 0x%x\n", status);
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
*BaseAddress = toGuestPtr(baseAddress);
|
||||||
|
*RegionSize = static_cast<SIZE_T>(regionSize);
|
||||||
|
|
||||||
DEBUG_LOG("-> 0x%x\n", STATUS_SUCCESS);
|
DEBUG_LOG("-> 0x%x\n", STATUS_SUCCESS);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PSIZE_T NumberOfBytesToProtect,
|
NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE ProcessHandle, GUEST_PTR *BaseAddress, PSIZE_T NumberOfBytesToProtect,
|
||||||
ULONG NewAccessProtection, PULONG OldAccessProtection) {
|
ULONG NewAccessProtection, PULONG OldAccessProtection) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("NtProtectVirtualMemory(%p, %p, %p, %lu, %p) ", ProcessHandle, BaseAddress, NumberOfBytesToProtect,
|
DEBUG_LOG("NtProtectVirtualMemory(%p, %p, %p, %lu, %p) ", ProcessHandle, BaseAddress, NumberOfBytesToProtect,
|
||||||
@@ -303,8 +307,8 @@ NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress,
|
|||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *base = *BaseAddress;
|
void *base = fromGuestPtr(*BaseAddress);
|
||||||
std::size_t length = static_cast<std::size_t>(*NumberOfBytesToProtect);
|
size_t length = static_cast<size_t>(*NumberOfBytesToProtect);
|
||||||
wibo::heap::VmStatus vmStatus =
|
wibo::heap::VmStatus vmStatus =
|
||||||
wibo::heap::virtualProtect(base, length, static_cast<DWORD>(NewAccessProtection), OldAccessProtection);
|
wibo::heap::virtualProtect(base, length, static_cast<DWORD>(NewAccessProtection), OldAccessProtection);
|
||||||
if (vmStatus != wibo::heap::VmStatus::Success) {
|
if (vmStatus != wibo::heap::VmStatus::Success) {
|
||||||
@@ -351,7 +355,7 @@ NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS
|
|||||||
PVOID ProcessInformation, ULONG ProcessInformationLength,
|
PVOID ProcessInformation, ULONG ProcessInformationLength,
|
||||||
PULONG ReturnLength) {
|
PULONG ReturnLength) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("NtQueryInformationProcess(%p, %u, %p, %u, %p) ", ProcessHandle, ProcessInformationClass,
|
DEBUG_LOG("NtQueryInformationProcess(%d, %u, %p, %u, %p) ", ProcessHandle, ProcessInformationClass,
|
||||||
ProcessInformation, ProcessInformationLength, ReturnLength);
|
ProcessInformation, ProcessInformationLength, ReturnLength);
|
||||||
if (!ProcessInformation) {
|
if (!ProcessInformation) {
|
||||||
DEBUG_LOG("-> 0x%x\n", STATUS_INVALID_PARAMETER);
|
DEBUG_LOG("-> 0x%x\n", STATUS_INVALID_PARAMETER);
|
||||||
@@ -378,7 +382,7 @@ NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS
|
|||||||
auto *info = reinterpret_cast<PROCESS_BASIC_INFORMATION *>(ProcessInformation);
|
auto *info = reinterpret_cast<PROCESS_BASIC_INFORMATION *>(ProcessInformation);
|
||||||
std::memset(info, 0, sizeof(*info));
|
std::memset(info, 0, sizeof(*info));
|
||||||
info->ExitStatus = static_cast<NTSTATUS>(details.exitCode);
|
info->ExitStatus = static_cast<NTSTATUS>(details.exitCode);
|
||||||
info->PebBaseAddress = details.peb;
|
info->PebBaseAddress = toGuestPtr(details.peb);
|
||||||
DWORD_PTR processMask = 0;
|
DWORD_PTR processMask = 0;
|
||||||
DWORD_PTR systemMask = 0;
|
DWORD_PTR systemMask = 0;
|
||||||
if (kernel32::GetProcessAffinityMask(ProcessHandle, &processMask, &systemMask)) {
|
if (kernel32::GetProcessAffinityMask(ProcessHandle, &processMask, &systemMask)) {
|
||||||
@@ -440,7 +444,7 @@ NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS
|
|||||||
size_t characterCount = widePath.empty() ? 0 : widePath.size() - 1;
|
size_t characterCount = widePath.empty() ? 0 : widePath.size() - 1;
|
||||||
unicode->Length = static_cast<unsigned short>(characterCount * sizeof(uint16_t));
|
unicode->Length = static_cast<unsigned short>(characterCount * sizeof(uint16_t));
|
||||||
unicode->MaximumLength = static_cast<unsigned short>(widePath.size() * sizeof(uint16_t));
|
unicode->MaximumLength = static_cast<unsigned short>(widePath.size() * sizeof(uint16_t));
|
||||||
unicode->Buffer = buffer;
|
unicode->Buffer = toGuestPtr(buffer);
|
||||||
DEBUG_LOG("-> 0x%x\n", STATUS_SUCCESS);
|
DEBUG_LOG("-> 0x%x\n", STATUS_SUCCESS);
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
11
dll/ntdll.h
11
dll/ntdll.h
@@ -7,7 +7,7 @@ using PIO_APC_ROUTINE = PVOID;
|
|||||||
typedef struct _IO_STATUS_BLOCK {
|
typedef struct _IO_STATUS_BLOCK {
|
||||||
union {
|
union {
|
||||||
NTSTATUS Status;
|
NTSTATUS Status;
|
||||||
PVOID Pointer;
|
GUEST_PTR Pointer;
|
||||||
};
|
};
|
||||||
ULONG_PTR Information;
|
ULONG_PTR Information;
|
||||||
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
|
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
|
||||||
@@ -38,12 +38,13 @@ NTSTATUS WINAPI NtReadFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcR
|
|||||||
NTSTATUS WINAPI NtWriteFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext,
|
NTSTATUS WINAPI NtWriteFile(HANDLE FileHandle, HANDLE Event, PIO_APC_ROUTINE ApcRoutine, PVOID ApcContext,
|
||||||
PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset,
|
PIO_STATUS_BLOCK IoStatusBlock, PVOID Buffer, ULONG Length, PLARGE_INTEGER ByteOffset,
|
||||||
PULONG Key);
|
PULONG Key);
|
||||||
NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, ULONG_PTR ZeroBits, PSIZE_T RegionSize,
|
NTSTATUS WINAPI NtAllocateVirtualMemory(HANDLE ProcessHandle, GUEST_PTR *BaseAddress, ULONG_PTR ZeroBits,
|
||||||
ULONG AllocationType, ULONG Protect);
|
PSIZE_T RegionSize, ULONG AllocationType, ULONG Protect);
|
||||||
NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE ProcessHandle, PVOID *BaseAddress, PSIZE_T NumberOfBytesToProtect,
|
NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE ProcessHandle, GUEST_PTR *BaseAddress, PSIZE_T NumberOfBytesToProtect,
|
||||||
ULONG NewAccessProtection, PULONG OldAccessProtection);
|
ULONG NewAccessProtection, PULONG OldAccessProtection);
|
||||||
NTSTATUS WINAPI RtlGetVersion(PRTL_OSVERSIONINFOW lpVersionInformation);
|
NTSTATUS WINAPI RtlGetVersion(PRTL_OSVERSIONINFOW lpVersionInformation);
|
||||||
NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass,
|
NTSTATUS WINAPI NtQueryInformationProcess(HANDLE ProcessHandle, PROCESSINFOCLASS ProcessInformationClass,
|
||||||
PVOID ProcessInformation, ULONG ProcessInformationLength, PULONG ReturnLength);
|
PVOID ProcessInformation, ULONG ProcessInformationLength,
|
||||||
|
PULONG ReturnLength);
|
||||||
|
|
||||||
} // namespace ntdll
|
} // namespace ntdll
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ HRESULT WINAPI CoInitialize(LPVOID pvReserved) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
HRESULT WINAPI CoCreateInstance(const GUID *rclsid, LPVOID pUnkOuter, DWORD dwClsContext, const GUID *riid,
|
HRESULT WINAPI CoCreateInstance(const GUID *rclsid, LPVOID pUnkOuter, DWORD dwClsContext, const GUID *riid,
|
||||||
LPVOID *ppv) {
|
GUEST_PTR *ppv) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("STUB: CoCreateInstance(0x%x, %p, %d, 0x%x, %p)\n", rclsid->Data1, pUnkOuter, dwClsContext, riid->Data1,
|
DEBUG_LOG("STUB: CoCreateInstance(0x%x, %p, %d, 0x%x, %p)\n", rclsid->Data1, pUnkOuter, dwClsContext, riid->Data1,
|
||||||
*ppv);
|
*ppv);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
namespace ole32 {
|
namespace ole32 {
|
||||||
|
|
||||||
HRESULT WINAPI CoInitialize(LPVOID pvReserved);
|
HRESULT WINAPI CoInitialize(LPVOID pvReserved);
|
||||||
HRESULT WINAPI CoCreateInstance(const GUID *rclsid, LPVOID pUnkOuter, DWORD dwClsContext, const GUID *riid, LPVOID *ppv);
|
HRESULT WINAPI CoCreateInstance(const GUID *rclsid, LPVOID pUnkOuter, DWORD dwClsContext, const GUID *riid, GUEST_PTR *ppv);
|
||||||
HRESULT WINAPI CLSIDFromString(LPCWSTR lpsz, GUID *pclsid);
|
HRESULT WINAPI CLSIDFromString(LPCWSTR lpsz, GUID *pclsid);
|
||||||
|
|
||||||
} // namespace ole32
|
} // namespace ole32
|
||||||
|
|||||||
@@ -4,8 +4,8 @@
|
|||||||
#include "context.h"
|
#include "context.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
#include "modules.h"
|
#include "modules.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
#include <cstdarg>
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -44,7 +44,7 @@ struct BindingHandleData {
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<RPC_WSTR, BindingComponents> g_stringBindings;
|
std::unordered_map<RPC_WSTR, BindingComponents> g_stringBindings;
|
||||||
std::unordered_map<RPC_BINDING_HANDLE, std::unique_ptr<BindingHandleData>> g_bindingHandles;
|
std::unordered_map<RPC_BINDING_HANDLE, wibo::heap::guest_ptr<BindingHandleData>> g_bindingHandles;
|
||||||
|
|
||||||
std::u16string toU16(RPC_WSTR str) {
|
std::u16string toU16(RPC_WSTR str) {
|
||||||
if (!str) {
|
if (!str) {
|
||||||
@@ -112,7 +112,7 @@ BindingHandleData *getBinding(RPC_BINDING_HANDLE handle) {
|
|||||||
namespace rpcrt4 {
|
namespace rpcrt4 {
|
||||||
|
|
||||||
RPC_STATUS WINAPI RpcStringBindingComposeW(RPC_WSTR objUuid, RPC_WSTR protSeq, RPC_WSTR networkAddr, RPC_WSTR endpoint,
|
RPC_STATUS WINAPI RpcStringBindingComposeW(RPC_WSTR objUuid, RPC_WSTR protSeq, RPC_WSTR networkAddr, RPC_WSTR endpoint,
|
||||||
RPC_WSTR options, RPC_WSTR *stringBinding) {
|
RPC_WSTR options, GUEST_PTR *stringBinding) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
BindingComponents components;
|
BindingComponents components;
|
||||||
components.objectUuid = toU16(objUuid);
|
components.objectUuid = toU16(objUuid);
|
||||||
@@ -136,18 +136,18 @@ RPC_STATUS WINAPI RpcStringBindingComposeW(RPC_WSTR objUuid, RPC_WSTR protSeq, R
|
|||||||
buffer[length] = 0;
|
buffer[length] = 0;
|
||||||
RPC_WSTR result = reinterpret_cast<RPC_WSTR>(buffer);
|
RPC_WSTR result = reinterpret_cast<RPC_WSTR>(buffer);
|
||||||
g_stringBindings[result] = components;
|
g_stringBindings[result] = components;
|
||||||
*stringBinding = result;
|
*stringBinding = toGuestPtr(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
return RPC_S_OK;
|
return RPC_S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
RPC_STATUS WINAPI RpcBindingFromStringBindingW(RPC_WSTR stringBinding, RPC_BINDING_HANDLE *binding) {
|
RPC_STATUS WINAPI RpcBindingFromStringBindingW(RPC_WSTR stringBinding, GUEST_PTR *binding) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
if (!binding) {
|
if (!binding) {
|
||||||
return RPC_S_INVALID_ARG;
|
return RPC_S_INVALID_ARG;
|
||||||
}
|
}
|
||||||
*binding = nullptr;
|
*binding = GUEST_NULL;
|
||||||
if (!stringBinding) {
|
if (!stringBinding) {
|
||||||
return RPC_S_INVALID_STRING_BINDING;
|
return RPC_S_INVALID_STRING_BINDING;
|
||||||
}
|
}
|
||||||
@@ -155,13 +155,13 @@ RPC_STATUS WINAPI RpcBindingFromStringBindingW(RPC_WSTR stringBinding, RPC_BINDI
|
|||||||
if (it == g_stringBindings.end()) {
|
if (it == g_stringBindings.end()) {
|
||||||
return RPC_S_INVALID_STRING_BINDING;
|
return RPC_S_INVALID_STRING_BINDING;
|
||||||
}
|
}
|
||||||
auto handleData = std::make_unique<BindingHandleData>();
|
auto handleData = wibo::heap::make_guest_unique<BindingHandleData>();
|
||||||
handleData->components = it->second;
|
handleData->components = it->second;
|
||||||
handleData->bindingString = composeString(handleData->components);
|
handleData->bindingString = composeString(handleData->components);
|
||||||
handleData->serverReachable = false;
|
handleData->serverReachable = false;
|
||||||
RPC_BINDING_HANDLE handle = reinterpret_cast<RPC_BINDING_HANDLE>(handleData.get());
|
RPC_BINDING_HANDLE handle = reinterpret_cast<RPC_BINDING_HANDLE>(handleData.get());
|
||||||
g_bindingHandles.emplace(handle, std::move(handleData));
|
g_bindingHandles.emplace(handle, std::move(handleData));
|
||||||
*binding = handle;
|
*binding = toGuestPtr(handle);
|
||||||
DEBUG_LOG("RpcBindingFromStringBindingW(handle=%p)\n", handle);
|
DEBUG_LOG("RpcBindingFromStringBindingW(handle=%p)\n", handle);
|
||||||
return RPC_S_OK;
|
return RPC_S_OK;
|
||||||
}
|
}
|
||||||
@@ -190,12 +190,12 @@ RPC_STATUS WINAPI RpcBindingSetAuthInfoExW(RPC_BINDING_HANDLE binding, RPC_WSTR
|
|||||||
return RPC_S_OK;
|
return RPC_S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
RPC_STATUS WINAPI RpcBindingFree(RPC_BINDING_HANDLE *binding) {
|
RPC_STATUS WINAPI RpcBindingFree(GUEST_PTR *binding) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
if (!binding) {
|
if (!binding) {
|
||||||
return RPC_S_INVALID_ARG;
|
return RPC_S_INVALID_ARG;
|
||||||
}
|
}
|
||||||
RPC_BINDING_HANDLE handle = *binding;
|
RPC_BINDING_HANDLE handle = reinterpret_cast<RPC_BINDING_HANDLE>(fromGuestPtr(*binding));
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
return RPC_S_INVALID_BINDING;
|
return RPC_S_INVALID_BINDING;
|
||||||
}
|
}
|
||||||
@@ -204,17 +204,17 @@ RPC_STATUS WINAPI RpcBindingFree(RPC_BINDING_HANDLE *binding) {
|
|||||||
return RPC_S_INVALID_BINDING;
|
return RPC_S_INVALID_BINDING;
|
||||||
}
|
}
|
||||||
g_bindingHandles.erase(it);
|
g_bindingHandles.erase(it);
|
||||||
*binding = nullptr;
|
*binding = GUEST_NULL;
|
||||||
DEBUG_LOG("RpcBindingFree\n");
|
DEBUG_LOG("RpcBindingFree\n");
|
||||||
return RPC_S_OK;
|
return RPC_S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
RPC_STATUS WINAPI RpcStringFreeW(RPC_WSTR *string) {
|
RPC_STATUS WINAPI RpcStringFreeW(GUEST_PTR *string) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
if (!string) {
|
if (!string) {
|
||||||
return RPC_S_INVALID_ARG;
|
return RPC_S_INVALID_ARG;
|
||||||
}
|
}
|
||||||
RPC_WSTR value = *string;
|
RPC_WSTR value = reinterpret_cast<RPC_WSTR>(fromGuestPtr(*string));
|
||||||
if (!value) {
|
if (!value) {
|
||||||
return RPC_S_OK;
|
return RPC_S_OK;
|
||||||
}
|
}
|
||||||
@@ -223,7 +223,7 @@ RPC_STATUS WINAPI RpcStringFreeW(RPC_WSTR *string) {
|
|||||||
g_stringBindings.erase(it);
|
g_stringBindings.erase(it);
|
||||||
}
|
}
|
||||||
std::free(reinterpret_cast<void *>(value));
|
std::free(reinterpret_cast<void *>(value));
|
||||||
*string = nullptr;
|
*string = GUEST_NULL;
|
||||||
return RPC_S_OK;
|
return RPC_S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
14
dll/rpcrt4.h
14
dll/rpcrt4.h
@@ -15,25 +15,27 @@ struct RPC_SECURITY_QOS {
|
|||||||
ULONG Capabilities;
|
ULONG Capabilities;
|
||||||
ULONG IdentityTracking;
|
ULONG IdentityTracking;
|
||||||
ULONG ImpersonationType;
|
ULONG ImpersonationType;
|
||||||
PVOID AdditionalSecurityInfo;
|
GUEST_PTR AdditionalSecurityInfo;
|
||||||
};
|
};
|
||||||
|
|
||||||
union CLIENT_CALL_RETURN {
|
union CLIENT_CALL_RETURN {
|
||||||
PVOID Pointer;
|
GUEST_PTR Pointer;
|
||||||
LONG_PTR Simple;
|
LONG_PTR Simple;
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace rpcrt4 {
|
namespace rpcrt4 {
|
||||||
|
|
||||||
RPC_STATUS WINAPI RpcStringBindingComposeW(RPC_WSTR objUuid, RPC_WSTR protSeq, RPC_WSTR networkAddr, RPC_WSTR endpoint,
|
RPC_STATUS WINAPI RpcStringBindingComposeW(RPC_WSTR objUuid, RPC_WSTR protSeq, RPC_WSTR networkAddr, RPC_WSTR endpoint,
|
||||||
RPC_WSTR options, RPC_WSTR *stringBinding);
|
RPC_WSTR options, GUEST_PTR *stringBinding);
|
||||||
RPC_STATUS WINAPI RpcBindingFromStringBindingW(RPC_WSTR stringBinding, RPC_BINDING_HANDLE *binding);
|
RPC_STATUS WINAPI RpcBindingFromStringBindingW(RPC_WSTR stringBinding, GUEST_PTR *binding);
|
||||||
RPC_STATUS WINAPI RpcBindingSetAuthInfoExW(RPC_BINDING_HANDLE binding, RPC_WSTR serverPrincName, ULONG authnLevel,
|
RPC_STATUS WINAPI RpcBindingSetAuthInfoExW(RPC_BINDING_HANDLE binding, RPC_WSTR serverPrincName, ULONG authnLevel,
|
||||||
ULONG authnSvc, RPC_AUTH_IDENTITY_HANDLE authIdentity, ULONG authzSvc,
|
ULONG authnSvc, RPC_AUTH_IDENTITY_HANDLE authIdentity, ULONG authzSvc,
|
||||||
RPC_SECURITY_QOS *securityQos);
|
RPC_SECURITY_QOS *securityQos);
|
||||||
RPC_STATUS WINAPI RpcBindingFree(RPC_BINDING_HANDLE *binding);
|
RPC_STATUS WINAPI RpcBindingFree(GUEST_PTR *binding);
|
||||||
RPC_STATUS WINAPI RpcStringFreeW(RPC_WSTR *string);
|
RPC_STATUS WINAPI RpcStringFreeW(GUEST_PTR *string);
|
||||||
|
#ifndef __x86_64__ // TODO
|
||||||
CLIENT_CALL_RETURN CDECL_NO_CONV NdrClientCall2(PMIDL_STUB_DESC stubDescriptor, PFORMAT_STRING format, ...);
|
CLIENT_CALL_RETURN CDECL_NO_CONV NdrClientCall2(PMIDL_STUB_DESC stubDescriptor, PFORMAT_STRING format, ...);
|
||||||
|
#endif
|
||||||
VOID WINAPI NdrServerCall2(PRPC_MESSAGE message);
|
VOID WINAPI NdrServerCall2(PRPC_MESSAGE message);
|
||||||
|
|
||||||
} // namespace rpcrt4
|
} // namespace rpcrt4
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
namespace user32 {
|
namespace user32 {
|
||||||
|
|
||||||
constexpr uint32_t RT_STRING_ID = 6;
|
constexpr uint32_t RT_STRING_ID = 6;
|
||||||
constexpr uintptr_t kDefaultKeyboardLayout = 0x04090409;
|
constexpr HKL kDefaultKeyboardLayout = 0x04090409;
|
||||||
constexpr int UOI_FLAGS = 1;
|
constexpr int UOI_FLAGS = 1;
|
||||||
constexpr DWORD WSF_VISIBLE = 0x0001;
|
constexpr DWORD WSF_VISIBLE = 0x0001;
|
||||||
|
|
||||||
@@ -135,15 +135,14 @@ int WINAPI MessageBoxA(HWND hwnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType) {
|
|||||||
|
|
||||||
HKL WINAPI GetKeyboardLayout(DWORD idThread) {
|
HKL WINAPI GetKeyboardLayout(DWORD idThread) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("GetKeyboardLayout(%u)\n", idThread);
|
DEBUG_LOG("STUB: GetKeyboardLayout(%u)\n", idThread);
|
||||||
(void)idThread;
|
(void)idThread;
|
||||||
return reinterpret_cast<HKL>(kDefaultKeyboardLayout);
|
return kDefaultKeyboardLayout;
|
||||||
}
|
}
|
||||||
|
|
||||||
HWINSTA WINAPI GetProcessWindowStation() {
|
HWINSTA WINAPI GetProcessWindowStation() {
|
||||||
DEBUG_LOG("GetProcessWindowStation()\n");
|
DEBUG_LOG("STUB: GetProcessWindowStation()\n");
|
||||||
static int kWindowStationStub;
|
return NO_HANDLE;
|
||||||
return reinterpret_cast<HWINSTA>(&kWindowStationStub);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL WINAPI GetUserObjectInformationA(HANDLE hObj, int nIndex, PVOID pvInfo, DWORD nLength, LPDWORD lpnLengthNeeded) {
|
BOOL WINAPI GetUserObjectInformationA(HANDLE hObj, int nIndex, PVOID pvInfo, DWORD nLength, LPDWORD lpnLengthNeeded) {
|
||||||
@@ -173,7 +172,7 @@ BOOL WINAPI GetUserObjectInformationA(HANDLE hObj, int nIndex, PVOID pvInfo, DWO
|
|||||||
|
|
||||||
HWND WINAPI GetActiveWindow() {
|
HWND WINAPI GetActiveWindow() {
|
||||||
DEBUG_LOG("GetActiveWindow()\n");
|
DEBUG_LOG("GetActiveWindow()\n");
|
||||||
return nullptr;
|
return NO_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace user32
|
} // namespace user32
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "modules.h"
|
#include "modules.h"
|
||||||
#include "resources.h"
|
#include "resources.h"
|
||||||
#include "strutil.h"
|
#include "strutil.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
@@ -239,7 +240,7 @@ UINT WINAPI GetFileVersionInfoA(LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwL
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int VerQueryValueImpl(const void *pBlock, const std::string &subBlock, void **lplpBuffer,
|
static unsigned int VerQueryValueImpl(const void *pBlock, const std::string &subBlock, GUEST_PTR *lplpBuffer,
|
||||||
unsigned int *puLen) {
|
unsigned int *puLen) {
|
||||||
if (!pBlock)
|
if (!pBlock)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -264,20 +265,20 @@ static unsigned int VerQueryValueImpl(const void *pBlock, const std::string &sub
|
|||||||
std::string narrow = wideStringToString(reinterpret_cast<const uint16_t *>(outPtr), static_cast<int>(outLen));
|
std::string narrow = wideStringToString(reinterpret_cast<const uint16_t *>(outPtr), static_cast<int>(outLen));
|
||||||
std::memcpy(dest, narrow.c_str(), narrow.size() + 1);
|
std::memcpy(dest, narrow.c_str(), narrow.size() + 1);
|
||||||
if (lplpBuffer)
|
if (lplpBuffer)
|
||||||
*lplpBuffer = dest;
|
*lplpBuffer = toGuestPtr(dest);
|
||||||
if (puLen)
|
if (puLen)
|
||||||
*puLen = static_cast<unsigned int>(narrow.size());
|
*puLen = static_cast<unsigned int>(narrow.size());
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (lplpBuffer)
|
if (lplpBuffer)
|
||||||
*lplpBuffer = const_cast<uint8_t *>(outPtr);
|
*lplpBuffer = toGuestPtr(outPtr);
|
||||||
if (puLen)
|
if (puLen)
|
||||||
*puLen = outLen;
|
*puLen = outLen;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT WINAPI VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen) {
|
UINT WINAPI VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, GUEST_PTR *lplpBuffer, PUINT puLen) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
DEBUG_LOG("VerQueryValueA(%p, %s, %p, %p)\n", pBlock, lpSubBlock ? lpSubBlock : "(null)", lplpBuffer, puLen);
|
DEBUG_LOG("VerQueryValueA(%p, %s, %p, %p)\n", pBlock, lpSubBlock ? lpSubBlock : "(null)", lplpBuffer, puLen);
|
||||||
if (!lpSubBlock)
|
if (!lpSubBlock)
|
||||||
@@ -299,7 +300,7 @@ UINT WINAPI GetFileVersionInfoW(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dw
|
|||||||
return GetFileVersionInfoA(narrow.c_str(), dwHandle, dwLen, lpData);
|
return GetFileVersionInfoA(narrow.c_str(), dwHandle, dwLen, lpData);
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen) {
|
UINT WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, GUEST_PTR *lplpBuffer, PUINT puLen) {
|
||||||
HOST_CONTEXT_GUARD();
|
HOST_CONTEXT_GUARD();
|
||||||
if (!lpSubBlock)
|
if (!lpSubBlock)
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ namespace version {
|
|||||||
|
|
||||||
UINT WINAPI GetFileVersionInfoSizeA(LPCSTR lptstrFilename, LPDWORD lpdwHandle);
|
UINT WINAPI GetFileVersionInfoSizeA(LPCSTR lptstrFilename, LPDWORD lpdwHandle);
|
||||||
UINT WINAPI GetFileVersionInfoA(LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData);
|
UINT WINAPI GetFileVersionInfoA(LPCSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData);
|
||||||
UINT WINAPI VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen);
|
UINT WINAPI VerQueryValueA(LPCVOID pBlock, LPCSTR lpSubBlock, GUEST_PTR *lplpBuffer, PUINT puLen);
|
||||||
UINT WINAPI GetFileVersionInfoSizeW(LPCWSTR lptstrFilename, LPDWORD lpdwHandle);
|
UINT WINAPI GetFileVersionInfoSizeW(LPCWSTR lptstrFilename, LPDWORD lpdwHandle);
|
||||||
UINT WINAPI GetFileVersionInfoW(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData);
|
UINT WINAPI GetFileVersionInfoW(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData);
|
||||||
UINT WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, LPVOID *lplpBuffer, PUINT puLen);
|
UINT WINAPI VerQueryValueW(LPCVOID pBlock, LPCWSTR lpSubBlock, GUEST_PTR *lplpBuffer, PUINT puLen);
|
||||||
|
|
||||||
} // namespace version
|
} // namespace version
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
#include "files.h"
|
#include "files.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "errors.h"
|
||||||
#include "handles.h"
|
#include "handles.h"
|
||||||
#include "strutil.h"
|
#include "strutil.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <climits>
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
@@ -312,7 +312,7 @@ HANDLE getStdHandle(DWORD nStdHandle) {
|
|||||||
case STD_ERROR_HANDLE:
|
case STD_ERROR_HANDLE:
|
||||||
return stderrHandle;
|
return stderrHandle;
|
||||||
default:
|
default:
|
||||||
return (void *)0xFFFFFFFF;
|
return INVALID_HANDLE_VALUE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
#include "handles.h"
|
#include "handles.h"
|
||||||
|
#include "types.h"
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
@@ -12,7 +13,7 @@ constexpr uint32_t kCompatMaxIndex = (0xFFFFu >> kHandleAlignShift) - 1;
|
|||||||
constexpr uint32_t kQuarantineLen = 64;
|
constexpr uint32_t kQuarantineLen = 64;
|
||||||
|
|
||||||
inline uint32_t indexOf(HANDLE h) noexcept {
|
inline uint32_t indexOf(HANDLE h) noexcept {
|
||||||
uint32_t v = static_cast<uint32_t>(reinterpret_cast<uintptr_t>(h));
|
uint32_t v = static_cast<uint32_t>(h);
|
||||||
if (v == 0 || (v & ((1U << kHandleAlignShift) - 1)) != 0) {
|
if (v == 0 || (v & ((1U << kHandleAlignShift) - 1)) != 0) {
|
||||||
return UINT32_MAX;
|
return UINT32_MAX;
|
||||||
}
|
}
|
||||||
@@ -21,7 +22,7 @@ inline uint32_t indexOf(HANDLE h) noexcept {
|
|||||||
|
|
||||||
inline HANDLE makeHandle(uint32_t index) noexcept {
|
inline HANDLE makeHandle(uint32_t index) noexcept {
|
||||||
uint32_t v = (index + 1) << kHandleAlignShift;
|
uint32_t v = (index + 1) << kHandleAlignShift;
|
||||||
return reinterpret_cast<HANDLE>(static_cast<uintptr_t>(v));
|
return static_cast<HANDLE>(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isPseudo(HANDLE h) noexcept { return reinterpret_cast<int32_t>(h) < 0; }
|
inline bool isPseudo(HANDLE h) noexcept { return reinterpret_cast<int32_t>(h) < 0; }
|
||||||
@@ -83,7 +84,7 @@ HANDLE Handles::alloc(Pin<> obj, uint32_t grantedAccess, uint32_t flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Pin<> Handles::get(HANDLE h, HandleMeta *metaOut) {
|
Pin<> Handles::get(HANDLE h, HandleMeta *metaOut) {
|
||||||
if (h == nullptr || isPseudo(h)) {
|
if (h == NO_HANDLE || isPseudo(h)) {
|
||||||
return {}; // pseudo-handles have no entries
|
return {}; // pseudo-handles have no entries
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
29
src/heap.cpp
29
src/heap.cpp
@@ -35,6 +35,7 @@
|
|||||||
namespace {
|
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 kTopDownStart = 0x7F000000UL; // Just below 2GB
|
constexpr uintptr_t kTopDownStart = 0x7F000000UL; // Just below 2GB
|
||||||
constexpr uintptr_t kTwoGB = 0x80000000UL;
|
constexpr uintptr_t kTwoGB = 0x80000000UL;
|
||||||
constexpr std::size_t kGuestArenaSize = 512ULL * 1024ULL * 1024ULL; // 512 MiB
|
constexpr std::size_t kGuestArenaSize = 512ULL * 1024ULL * 1024ULL; // 512 MiB
|
||||||
@@ -195,7 +196,7 @@ bool overlapsExistingMapping(uintptr_t base, std::size_t length) {
|
|||||||
if (info.RegionSize == 0) {
|
if (info.RegionSize == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
uintptr_t mapStart = reinterpret_cast<uintptr_t>(info.BaseAddress);
|
uintptr_t mapStart = reinterpret_cast<uintptr_t>(fromGuestPtr(info.BaseAddress));
|
||||||
uintptr_t mapEnd = mapStart + static_cast<uintptr_t>(info.RegionSize);
|
uintptr_t mapEnd = mapStart + static_cast<uintptr_t>(info.RegionSize);
|
||||||
if (mapEnd <= base) {
|
if (mapEnd <= base) {
|
||||||
continue;
|
continue;
|
||||||
@@ -214,8 +215,8 @@ void recordGuestMapping(uintptr_t base, std::size_t size, DWORD allocationProtec
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
MEMORY_BASIC_INFORMATION info{};
|
MEMORY_BASIC_INFORMATION info{};
|
||||||
info.BaseAddress = reinterpret_cast<void *>(base);
|
info.BaseAddress = toGuestPtr(reinterpret_cast<void *>(base));
|
||||||
info.AllocationBase = reinterpret_cast<void *>(base);
|
info.AllocationBase = toGuestPtr(reinterpret_cast<void *>(base));
|
||||||
info.AllocationProtect = allocationProtect;
|
info.AllocationProtect = allocationProtect;
|
||||||
info.RegionSize = size;
|
info.RegionSize = size;
|
||||||
info.State = state;
|
info.State = state;
|
||||||
@@ -435,7 +436,7 @@ void initializeImpl() {
|
|||||||
|
|
||||||
// Map and register guest arena (below 2GB, exclusive)
|
// Map and register guest arena (below 2GB, exclusive)
|
||||||
ArenaRange guest;
|
ArenaRange guest;
|
||||||
if (mapArena(kGuestArenaSize, kLowMemoryStart, kTopDownStart, true, "wibo guest arena", guest)) {
|
if (mapArena(kGuestArenaSize, kLowMemoryStart, kHeapMax, true, "wibo guest arena", guest)) {
|
||||||
bool ok = mi_manage_os_memory_ex(guest.start, guest.size,
|
bool ok = mi_manage_os_memory_ex(guest.start, guest.size,
|
||||||
/*is_committed*/ false,
|
/*is_committed*/ false,
|
||||||
/*is_pinned*/ false,
|
/*is_pinned*/ false,
|
||||||
@@ -910,8 +911,8 @@ VmStatus virtualQuery(const void *address, MEMORY_BASIC_INFORMATION *outInfo) {
|
|||||||
regionEnd = regionStart + pageSize;
|
regionEnd = regionStart + pageSize;
|
||||||
}
|
}
|
||||||
allocLock.unlock();
|
allocLock.unlock();
|
||||||
outInfo->BaseAddress = reinterpret_cast<void *>(regionStart);
|
outInfo->BaseAddress = toGuestPtr(reinterpret_cast<void *>(regionStart));
|
||||||
outInfo->AllocationBase = nullptr;
|
outInfo->AllocationBase = GUEST_NULL;
|
||||||
outInfo->AllocationProtect = 0;
|
outInfo->AllocationProtect = 0;
|
||||||
outInfo->RegionSize = regionEnd - regionStart;
|
outInfo->RegionSize = regionEnd - regionStart;
|
||||||
outInfo->State = MEM_FREE;
|
outInfo->State = MEM_FREE;
|
||||||
@@ -961,8 +962,8 @@ VmStatus virtualQuery(const void *address, MEMORY_BASIC_INFORMATION *outInfo) {
|
|||||||
DWORD finalProtect = committed ? pageProtect : PAGE_NOACCESS;
|
DWORD finalProtect = committed ? pageProtect : PAGE_NOACCESS;
|
||||||
allocLock.unlock();
|
allocLock.unlock();
|
||||||
|
|
||||||
outInfo->BaseAddress = reinterpret_cast<void *>(blockStart);
|
outInfo->BaseAddress = toGuestPtr(reinterpret_cast<void *>(blockStart));
|
||||||
outInfo->AllocationBase = reinterpret_cast<void *>(region->base);
|
outInfo->AllocationBase = toGuestPtr(reinterpret_cast<void *>(region->base));
|
||||||
outInfo->AllocationProtect = allocationProtect;
|
outInfo->AllocationProtect = allocationProtect;
|
||||||
outInfo->RegionSize = blockEnd - blockStart;
|
outInfo->RegionSize = blockEnd - blockStart;
|
||||||
outInfo->State = committed ? MEM_COMMIT : MEM_RESERVE;
|
outInfo->State = committed ? MEM_COMMIT : MEM_RESERVE;
|
||||||
@@ -1153,7 +1154,7 @@ static size_t blockLower2GB(MEMORY_BASIC_INFORMATION mappings[MAX_NUM_MAPPINGS])
|
|||||||
if (numMappings < MAX_NUM_MAPPINGS) {
|
if (numMappings < MAX_NUM_MAPPINGS) {
|
||||||
if (numMappings > 0) {
|
if (numMappings > 0) {
|
||||||
auto &prevMapping = mappings[numMappings - 1];
|
auto &prevMapping = mappings[numMappings - 1];
|
||||||
uintptr_t prevMapStart = reinterpret_cast<uintptr_t>(prevMapping.BaseAddress);
|
uintptr_t prevMapStart = reinterpret_cast<uintptr_t>(fromGuestPtr(prevMapping.BaseAddress));
|
||||||
uintptr_t prevMapEnd = prevMapStart + prevMapping.RegionSize;
|
uintptr_t prevMapEnd = prevMapStart + prevMapping.RegionSize;
|
||||||
if (mapStart <= prevMapEnd) {
|
if (mapStart <= prevMapEnd) {
|
||||||
// Extend the previous mapping
|
// Extend the previous mapping
|
||||||
@@ -1164,10 +1165,10 @@ static size_t blockLower2GB(MEMORY_BASIC_INFORMATION mappings[MAX_NUM_MAPPINGS])
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
mappings[numMappings++] = (MEMORY_BASIC_INFORMATION){
|
mappings[numMappings++] = (MEMORY_BASIC_INFORMATION){
|
||||||
.BaseAddress = reinterpret_cast<void *>(mapStart),
|
.BaseAddress = toGuestPtr(reinterpret_cast<void *>(mapStart)),
|
||||||
.AllocationBase = reinterpret_cast<void *>(mapStart),
|
.AllocationBase = toGuestPtr(reinterpret_cast<void *>(mapStart)),
|
||||||
.AllocationProtect = PAGE_NOACCESS,
|
.AllocationProtect = PAGE_NOACCESS,
|
||||||
.RegionSize = mapEnd - mapStart,
|
.RegionSize = static_cast<SIZE_T>(mapEnd - mapStart),
|
||||||
.State = MEM_RESERVE,
|
.State = MEM_RESERVE,
|
||||||
.Protect = PAGE_NOACCESS,
|
.Protect = PAGE_NOACCESS,
|
||||||
.Type = 0, // external
|
.Type = 0, // external
|
||||||
@@ -1225,9 +1226,9 @@ __attribute__((used)) static void wibo_heap_constructor() {
|
|||||||
g_mappings = new std::map<uintptr_t, MEMORY_BASIC_INFORMATION>;
|
g_mappings = new std::map<uintptr_t, MEMORY_BASIC_INFORMATION>;
|
||||||
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=%p, RegionSize=%lu\n", i, mappings[i].BaseAddress,
|
fprintf(stderr, "Existing %zu: BaseAddress=%x, RegionSize=%u\n", i, mappings[i].BaseAddress,
|
||||||
mappings[i].RegionSize);
|
mappings[i].RegionSize);
|
||||||
}
|
}
|
||||||
g_mappings->emplace(reinterpret_cast<uintptr_t>(mappings[i].BaseAddress), mappings[i]);
|
g_mappings->emplace(reinterpret_cast<uintptr_t>(fromGuestPtr(mappings[i].BaseAddress)), mappings[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
98
src/heap.h
98
src/heap.h
@@ -5,6 +5,8 @@
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
#include <limits>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
struct mi_heap_s;
|
struct mi_heap_s;
|
||||||
typedef struct mi_heap_s mi_heap_t;
|
typedef struct mi_heap_s mi_heap_t;
|
||||||
@@ -50,4 +52,100 @@ NTSTATUS ntStatusFromVmStatus(VmStatus status);
|
|||||||
|
|
||||||
bool reserveGuestStack(std::size_t stackSizeBytes, void **outStackLimit, void **outStackBase);
|
bool reserveGuestStack(std::size_t stackSizeBytes, void **outStackLimit, void **outStackBase);
|
||||||
|
|
||||||
|
//-------------------- deleters --------------------
|
||||||
|
template <class U> struct single_deleter {
|
||||||
|
void operator()(U *p) const noexcept {
|
||||||
|
if (!p)
|
||||||
|
return;
|
||||||
|
p->~U();
|
||||||
|
wibo::heap::guestFree(static_cast<void *>(p));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class U> struct array_deleter {
|
||||||
|
std::size_t n{}; // number of elements
|
||||||
|
void operator()(U *p) const noexcept {
|
||||||
|
if (!p)
|
||||||
|
return;
|
||||||
|
for (std::size_t i = n; i > 0; --i)
|
||||||
|
(p + (i - 1))->~U();
|
||||||
|
wibo::heap::guestFree(static_cast<void *>(p));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
//-------------------- pointer alias picking T or T[] --------------------
|
||||||
|
template <class T> struct unique_type {
|
||||||
|
using type = std::unique_ptr<T, single_deleter<T>>;
|
||||||
|
};
|
||||||
|
template <class T> struct unique_type<T[]> {
|
||||||
|
using type = std::unique_ptr<T[], array_deleter<T>>;
|
||||||
|
};
|
||||||
|
// template <class T, std::size_t> struct unique_type<T[]>; // no bounded arrays (int[N])
|
||||||
|
|
||||||
|
template <class T> using guest_ptr = typename unique_type<T>::type;
|
||||||
|
|
||||||
|
//-------------------- helpers --------------------
|
||||||
|
inline bool mul_overflows(std::size_t a, std::size_t b) {
|
||||||
|
return b != 0 && a > (std::numeric_limits<std::size_t>::max)() / b;
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------- single object --------------------
|
||||||
|
template <class T, class... Args>
|
||||||
|
requires(!std::is_array_v<T>)
|
||||||
|
guest_ptr<T> make_guest_unique(Args &&...args) noexcept {
|
||||||
|
// Optional: insist on nothrow construction in a no-exception build
|
||||||
|
static_assert(std::is_nothrow_constructible_v<T, Args...>,
|
||||||
|
"T must be nothrow-constructible when exceptions are disabled");
|
||||||
|
|
||||||
|
void *raw = wibo::heap::guestMalloc(sizeof(T));
|
||||||
|
if (!raw)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// placement-new without exceptions
|
||||||
|
T *p = ::new (raw) T(std::forward<Args>(args)...);
|
||||||
|
return guest_ptr<T>(p, single_deleter<T>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------- unbounded array: default-construct --------------------
|
||||||
|
template <class T>
|
||||||
|
requires std::is_unbounded_array_v<T>
|
||||||
|
guest_ptr<T> make_guest_unique(std::size_t n) noexcept {
|
||||||
|
using U = std::remove_extent_t<T>;
|
||||||
|
static_assert(std::is_nothrow_default_constructible_v<U>,
|
||||||
|
"U must be nothrow default-constructible when exceptions are disabled");
|
||||||
|
|
||||||
|
if (mul_overflows(n, sizeof(U)))
|
||||||
|
return {};
|
||||||
|
void *raw = wibo::heap::guestMalloc(n * sizeof(U));
|
||||||
|
if (!raw)
|
||||||
|
return {};
|
||||||
|
U *p = static_cast<U *>(raw);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < n; ++i)
|
||||||
|
::new (p + i) U();
|
||||||
|
|
||||||
|
return guest_ptr<T>(p, array_deleter<U>{n});
|
||||||
|
}
|
||||||
|
|
||||||
|
//-------------------- unbounded array: per-element args --------------------
|
||||||
|
template <class T, class... Args>
|
||||||
|
requires std::is_unbounded_array_v<T>
|
||||||
|
guest_ptr<T> make_guest_unique(std::size_t n, Args &&...args) noexcept {
|
||||||
|
using U = std::remove_extent_t<T>;
|
||||||
|
static_assert(std::is_nothrow_constructible_v<U, Args...>,
|
||||||
|
"U(args...) must be nothrow-constructible when exceptions are disabled");
|
||||||
|
|
||||||
|
if (mul_overflows(n, sizeof(U)))
|
||||||
|
return {};
|
||||||
|
void *raw = wibo::heap::guestMalloc(n * sizeof(U));
|
||||||
|
if (!raw)
|
||||||
|
return {};
|
||||||
|
U *p = static_cast<U *>(raw);
|
||||||
|
|
||||||
|
for (std::size_t i = 0; i < n; ++i)
|
||||||
|
::new (p + i) U(std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
return guest_ptr<T>(p, array_deleter<U>{n});
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace wibo::heap
|
} // namespace wibo::heap
|
||||||
|
|||||||
@@ -86,11 +86,11 @@ struct PESectionHeader {
|
|||||||
uint32_t characteristics;
|
uint32_t characteristics;
|
||||||
};
|
};
|
||||||
struct PEImportDirectoryEntry {
|
struct PEImportDirectoryEntry {
|
||||||
uint32_t *importLookupTable;
|
uint32_t importLookupTable;
|
||||||
uint32_t timeDateStamp;
|
uint32_t timeDateStamp;
|
||||||
uint32_t forwarderChain;
|
uint32_t forwarderChain;
|
||||||
char *name;
|
uint32_t name;
|
||||||
uint32_t *importAddressTable;
|
uint32_t importAddressTable;
|
||||||
};
|
};
|
||||||
struct PEHintNameTableEntry {
|
struct PEHintNameTableEntry {
|
||||||
uint16_t hint;
|
uint16_t hint;
|
||||||
@@ -254,7 +254,9 @@ bool wibo::Executable::loadPE(FILE *file, bool exec) {
|
|||||||
allocStatus = wibo::heap::virtualAlloc(
|
allocStatus = wibo::heap::virtualAlloc(
|
||||||
&allocatedBase, &allocationSize, MEM_RESERVE | MEM_COMMIT, initialProtect, MEM_IMAGE);
|
&allocatedBase, &allocationSize, MEM_RESERVE | MEM_COMMIT, initialProtect, MEM_IMAGE);
|
||||||
}
|
}
|
||||||
if (allocStatus != wibo::heap::VmStatus::Success) {
|
if (allocStatus == wibo::heap::VmStatus::Success) {
|
||||||
|
DEBUG_LOG("loadPE: mapped image at %p\n", allocatedBase);
|
||||||
|
} else {
|
||||||
DEBUG_LOG("Image mapping failed (status=%u)\n", static_cast<unsigned>(allocStatus));
|
DEBUG_LOG("Image mapping failed (status=%u)\n", static_cast<unsigned>(allocStatus));
|
||||||
imageBase = nullptr;
|
imageBase = nullptr;
|
||||||
return false;
|
return false;
|
||||||
@@ -425,10 +427,10 @@ bool wibo::Executable::resolveImports() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (dir->name) {
|
while (dir->name) {
|
||||||
char *dllName = fromRVA(dir->name);
|
char *dllName = fromRVA<char>(dir->name);
|
||||||
DEBUG_LOG("DLL Name: %s\n", dllName);
|
DEBUG_LOG("DLL Name: %s\n", dllName);
|
||||||
uint32_t *lookupTable = fromRVA(dir->importLookupTable);
|
uint32_t *lookupTable = fromRVA<uint32_t>(dir->importLookupTable);
|
||||||
uint32_t *addressTable = fromRVA(dir->importAddressTable);
|
uint32_t *addressTable = fromRVA<uint32_t>(dir->importAddressTable);
|
||||||
|
|
||||||
ModuleInfo *module = loadModule(dllName);
|
ModuleInfo *module = loadModule(dllName);
|
||||||
if (!module && kernel32::getLastError() != ERROR_MOD_NOT_FOUND) {
|
if (!module && kernel32::getLastError() != ERROR_MOD_NOT_FOUND) {
|
||||||
|
|||||||
40
src/macros.S
Normal file
40
src/macros.S
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
.intel_syntax noprefix
|
||||||
|
|
||||||
|
.equ TEB_SELF, 0x18 # Self
|
||||||
|
.equ TEB_FS_SEL, 0xf98 # CurrentFsSelector
|
||||||
|
.equ TEB_GS_SEL, 0xf9a # CurrentGsSelector
|
||||||
|
|
||||||
|
#ifdef __i386__
|
||||||
|
|
||||||
|
.equ TEB_SP, 0xf9c # CurrentStackPointer
|
||||||
|
|
||||||
|
#endif // __i386__
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
|
||||||
|
.equ TEB_SP, 0xfa0 # CurrentStackPointer
|
||||||
|
.equ TEB_FSBASE, 0xfa8 # CurrentFsBase
|
||||||
|
|
||||||
|
.equ CS_32, 0x23 # 32-bit code segment (Linux)
|
||||||
|
.equ CS_64, 0x33 # 64-bit code segment (Linux)
|
||||||
|
.equ DS_32, 0x2b # 32-bit data segment (Linux)
|
||||||
|
|
||||||
|
.macro LJMP32
|
||||||
|
jmp fword ptr [rip] # far jump into 32-bit code
|
||||||
|
.long 1f # 32-bit code offset
|
||||||
|
.word CS_32 # 32-bit code segment (Linux)
|
||||||
|
.code32
|
||||||
|
1:
|
||||||
|
endbr32
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.macro LJMP64
|
||||||
|
push CS_64 # 64-bit code segment (Linux)
|
||||||
|
push offset 1f # 64-bit code offset
|
||||||
|
retf # far jump into 64-bit code
|
||||||
|
.code64
|
||||||
|
1:
|
||||||
|
endbr64
|
||||||
|
.endm
|
||||||
|
|
||||||
|
#endif // __x86_64__
|
||||||
54
src/main.cpp
54
src/main.cpp
@@ -1,5 +1,4 @@
|
|||||||
#include "common.h"
|
#include "common.h"
|
||||||
#include "context.h"
|
|
||||||
#include "entry.h"
|
#include "entry.h"
|
||||||
#include "entry_trampolines.h"
|
#include "entry_trampolines.h"
|
||||||
#include "files.h"
|
#include "files.h"
|
||||||
@@ -8,9 +7,15 @@
|
|||||||
#include "processes.h"
|
#include "processes.h"
|
||||||
#include "strutil.h"
|
#include "strutil.h"
|
||||||
#include "tls.h"
|
#include "tls.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/ldt.h>
|
||||||
|
#include <asm/prctl.h>
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
@@ -53,13 +58,13 @@ void wibo::debug_log(const char *fmt, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TEB *wibo::allocateTib() {
|
TEB *wibo::allocateTib() {
|
||||||
auto *newTib = static_cast<TEB *>(std::calloc(1, sizeof(TEB)));
|
auto *newTib = static_cast<TEB *>(wibo::heap::guestCalloc(1, sizeof(TEB)));
|
||||||
if (!newTib) {
|
if (!newTib) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
tls::initializeTib(newTib);
|
tls::initializeTib(newTib);
|
||||||
newTib->Tib.Self = &newTib->Tib;
|
newTib->Tib.Self = toGuestPtr(newTib);
|
||||||
newTib->Peb = processPeb;
|
newTib->Peb = toGuestPtr(processPeb);
|
||||||
return newTib;
|
return newTib;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,8 +87,8 @@ void wibo::initializeTibStackInfo(TEB *tibPtr) {
|
|||||||
fprintf(stderr, "Failed to reserve guest stack\n");
|
fprintf(stderr, "Failed to reserve guest stack\n");
|
||||||
std::abort();
|
std::abort();
|
||||||
}
|
}
|
||||||
tibPtr->Tib.StackLimit = guestLimit;
|
tibPtr->Tib.StackLimit = toGuestPtr(guestLimit);
|
||||||
tibPtr->Tib.StackBase = guestBase;
|
tibPtr->Tib.StackBase = toGuestPtr(guestBase);
|
||||||
tibPtr->CurrentStackPointer = guestBase;
|
tibPtr->CurrentStackPointer = guestBase;
|
||||||
DEBUG_LOG("initializeTibStackInfo: using guest stack base=%p limit=%p\n", tibPtr->Tib.StackBase,
|
DEBUG_LOG("initializeTibStackInfo: using guest stack base=%p limit=%p\n", tibPtr->Tib.StackBase,
|
||||||
tibPtr->Tib.StackLimit);
|
tibPtr->Tib.StackLimit);
|
||||||
@@ -94,10 +99,18 @@ bool wibo::installTibForCurrentThread(TEB *tibPtr) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
currentThreadTeb = tibPtr;
|
||||||
|
#ifdef __x86_64__
|
||||||
|
tibEntryNumber = x86_64_thread_setup(tibEntryNumber, tibPtr);
|
||||||
|
if (tibEntryNumber == -1 || tibPtr->CurrentFsSelector == 0) {
|
||||||
|
perror("x86_64_thread_setup failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
#else
|
||||||
struct user_desc desc;
|
struct user_desc desc;
|
||||||
std::memset(&desc, 0, sizeof(desc));
|
std::memset(&desc, 0, sizeof(desc));
|
||||||
desc.entry_number = tibEntryNumber;
|
desc.entry_number = tibEntryNumber;
|
||||||
desc.base_addr = reinterpret_cast<unsigned int>(tibPtr);
|
desc.base_addr = reinterpret_cast<uintptr_t>(tibPtr);
|
||||||
desc.limit = static_cast<unsigned int>(sizeof(TEB) - 1);
|
desc.limit = static_cast<unsigned int>(sizeof(TEB) - 1);
|
||||||
desc.seg_32bit = 1;
|
desc.seg_32bit = 1;
|
||||||
desc.contents = 0;
|
desc.contents = 0;
|
||||||
@@ -118,13 +131,10 @@ bool wibo::installTibForCurrentThread(TEB *tibPtr) {
|
|||||||
|
|
||||||
tibPtr->CurrentFsSelector = static_cast<uint16_t>((desc.entry_number << 3) | 3);
|
tibPtr->CurrentFsSelector = static_cast<uint16_t>((desc.entry_number << 3) | 3);
|
||||||
tibPtr->CurrentGsSelector = 0;
|
tibPtr->CurrentGsSelector = 0;
|
||||||
currentThreadTeb = tibPtr;
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make this global to ease debugging
|
|
||||||
TEB tib;
|
|
||||||
|
|
||||||
static std::string getExeName(const char *argv0) {
|
static std::string getExeName(const char *argv0) {
|
||||||
std::filesystem::path exePath(argv0 ? argv0 : "wibo");
|
std::filesystem::path exePath(argv0 ? argv0 : "wibo");
|
||||||
return exePath.filename().string();
|
return exePath.filename().string();
|
||||||
@@ -347,16 +357,18 @@ int main(int argc, char **argv) {
|
|||||||
|
|
||||||
files::init();
|
files::init();
|
||||||
|
|
||||||
|
// Create PEB
|
||||||
|
PEB *peb = reinterpret_cast<PEB *>(wibo::heap::guestCalloc(1, sizeof(PEB)));
|
||||||
|
peb->ProcessParameters = toGuestPtr(wibo::heap::guestCalloc(1, sizeof(RTL_USER_PROCESS_PARAMETERS)));
|
||||||
|
|
||||||
// Create TIB
|
// Create TIB
|
||||||
memset(&tib, 0, sizeof(tib));
|
TEB *tib = reinterpret_cast<TEB *>(wibo::heap::guestCalloc(1, sizeof(TEB)));
|
||||||
wibo::tls::initializeTib(&tib);
|
wibo::tls::initializeTib(tib);
|
||||||
tib.Tib.Self = &tib.Tib;
|
tib->Tib.Self = toGuestPtr(tib);
|
||||||
tib.Peb = static_cast<PEB *>(calloc(1, sizeof(PEB)));
|
tib->Peb = toGuestPtr(peb);
|
||||||
tib.Peb->ProcessParameters =
|
wibo::processPeb = peb;
|
||||||
static_cast<RTL_USER_PROCESS_PARAMETERS *>(calloc(1, sizeof(RTL_USER_PROCESS_PARAMETERS)));
|
wibo::initializeTibStackInfo(tib);
|
||||||
wibo::processPeb = tib.Peb;
|
if (!wibo::installTibForCurrentThread(tib)) {
|
||||||
wibo::initializeTibStackInfo(&tib);
|
|
||||||
if (!wibo::installTibForCurrentThread(&tib)) {
|
|
||||||
fprintf(stderr, "Failed to install TIB for main thread\n");
|
fprintf(stderr, "Failed to install TIB for main thread\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -506,7 +518,7 @@ int main(int argc, char **argv) {
|
|||||||
call_EntryProc(entryPoint);
|
call_EntryProc(entryPoint);
|
||||||
DEBUG_LOG("We came back\n");
|
DEBUG_LOG("We came back\n");
|
||||||
wibo::shutdownModuleRegistry();
|
wibo::shutdownModuleRegistry();
|
||||||
wibo::tls::cleanupTib(&tib);
|
wibo::tls::cleanupTib(tib);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
197
src/modules.cpp
197
src/modules.cpp
@@ -6,9 +6,11 @@
|
|||||||
#include "errors.h"
|
#include "errors.h"
|
||||||
#include "files.h"
|
#include "files.h"
|
||||||
#include "heap.h"
|
#include "heap.h"
|
||||||
|
#include "kernel32/errhandlingapi.h"
|
||||||
#include "kernel32/internal.h"
|
#include "kernel32/internal.h"
|
||||||
#include "strutil.h"
|
#include "strutil.h"
|
||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
@@ -38,8 +40,65 @@ extern const wibo::ModuleStub lib_user32;
|
|||||||
extern const wibo::ModuleStub lib_vcruntime;
|
extern const wibo::ModuleStub lib_vcruntime;
|
||||||
extern const wibo::ModuleStub lib_version;
|
extern const wibo::ModuleStub lib_version;
|
||||||
|
|
||||||
|
// setup.S
|
||||||
|
template <size_t Index> void stubThunk();
|
||||||
|
|
||||||
|
/*
|
||||||
|
apiset api-ms-win-core-crt-l1-1-0 = msvcrt.dll
|
||||||
|
apiset api-ms-win-core-crt-l2-1-0 = msvcrt.dll
|
||||||
|
apiset api-ms-win-crt-conio-l1-1-0 = msvcrt.dll
|
||||||
|
apiset api-ms-win-crt-convert-l1-1-0 = msvcrt.dll
|
||||||
|
apiset api-ms-win-crt-environment-l1-1-0 = ucrtbase.dll
|
||||||
|
apiset api-ms-win-crt-filesystem-l1-1-0 = ucrtbase.dll
|
||||||
|
apiset api-ms-win-crt-heap-l1-1-0 = ucrtbase.dll
|
||||||
|
apiset api-ms-win-crt-locale-l1-1-0 = ucrtbase.dll
|
||||||
|
apiset api-ms-win-crt-math-l1-1-0 = ucrtbase.dll
|
||||||
|
apiset api-ms-win-crt-multibyte-l1-1-0 = ucrtbase.dll
|
||||||
|
apiset api-ms-win-crt-private-l1-1-0 = ucrtbase.dll
|
||||||
|
apiset api-ms-win-crt-process-l1-1-0 = ucrtbase.dll
|
||||||
|
apiset api-ms-win-crt-runtime-l1-1-0 = ucrtbase.dll
|
||||||
|
apiset api-ms-win-crt-stdio-l1-1-0 = ucrtbase.dll
|
||||||
|
apiset api-ms-win-crt-string-l1-1-0 = ucrtbase.dll
|
||||||
|
apiset api-ms-win-crt-time-l1-1-0 = ucrtbase.dll
|
||||||
|
apiset api-ms-win-crt-utility-l1-1-0 = ucrtbase.dll
|
||||||
|
*/
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
const std::array<std::pair<std::string_view, std::string_view>, 17> kApiSet = {
|
||||||
|
std::pair{"api-ms-win-core-crt-l1-1-0.dll", "msvcrt.dll"},
|
||||||
|
std::pair{"api-ms-win-core-crt-l2-1-0.dll", "msvcrt.dll"},
|
||||||
|
std::pair{"api-ms-win-crt-conio-l1-1-0.dll", "msvcrt.dll"},
|
||||||
|
std::pair{"api-ms-win-crt-convert-l1-1-0.dll", "msvcrt.dll"},
|
||||||
|
std::pair{"api-ms-win-crt-environment-l1-1-0.dll", "ucrtbase.dll"},
|
||||||
|
std::pair{"api-ms-win-crt-filesystem-l1-1-0.dll", "ucrtbase.dll"},
|
||||||
|
std::pair{"api-ms-win-crt-heap-l1-1-0.dll", "ucrtbase.dll"},
|
||||||
|
std::pair{"api-ms-win-crt-locale-l1-1-0.dll", "ucrtbase.dll"},
|
||||||
|
std::pair{"api-ms-win-crt-math-l1-1-0.dll", "ucrtbase.dll"},
|
||||||
|
std::pair{"api-ms-win-crt-multibyte-l1-1-0.dll", "ucrtbase.dll"},
|
||||||
|
std::pair{"api-ms-win-crt-private-l1-1-0.dll", "ucrtbase.dll"},
|
||||||
|
std::pair{"api-ms-win-crt-process-l1-1-0.dll", "ucrtbase.dll"},
|
||||||
|
std::pair{"api-ms-win-crt-runtime-l1-1-0.dll", "ucrtbase.dll"},
|
||||||
|
std::pair{"api-ms-win-crt-stdio-l1-1-0.dll", "ucrtbase.dll"},
|
||||||
|
std::pair{"api-ms-win-crt-string-l1-1-0.dll", "ucrtbase.dll"},
|
||||||
|
std::pair{"api-ms-win-crt-time-l1-1-0.dll", "ucrtbase.dll"},
|
||||||
|
std::pair{"api-ms-win-crt-utility-l1-1-0.dll", "ucrtbase.dll"},
|
||||||
|
};
|
||||||
|
|
||||||
|
const std::array<std::pair<std::string_view, std::string_view>, 11> kFallbacks = {
|
||||||
|
std::pair{"ucrtbase.dll", "msvcrt.dll"},
|
||||||
|
std::pair{"msvcrt40.dll", "msvcrt.dll"},
|
||||||
|
std::pair{"msvcr70.dll", "msvcrt.dll"},
|
||||||
|
std::pair{"msvcr71.dll", "msvcrt.dll"},
|
||||||
|
std::pair{"msvcr80.dll", "msvcrt.dll"},
|
||||||
|
std::pair{"msvcr90.dll", "msvcrt.dll"},
|
||||||
|
std::pair{"msvcr100.dll", "msvcrt.dll"},
|
||||||
|
std::pair{"msvcr110.dll", "msvcrt.dll"},
|
||||||
|
std::pair{"msvcr120.dll", "msvcrt.dll"},
|
||||||
|
std::pair{"msvcr130.dll", "msvcrt.dll"},
|
||||||
|
std::pair{"msvcr140.dll", "msvcrt.dll"},
|
||||||
|
};
|
||||||
|
|
||||||
constexpr DWORD DLL_PROCESS_DETACH = 0;
|
constexpr DWORD DLL_PROCESS_DETACH = 0;
|
||||||
constexpr DWORD DLL_PROCESS_ATTACH = 1;
|
constexpr DWORD DLL_PROCESS_ATTACH = 1;
|
||||||
constexpr DWORD DLL_THREAD_ATTACH = 2;
|
constexpr DWORD DLL_THREAD_ATTACH = 2;
|
||||||
@@ -69,6 +128,8 @@ size_t stubIndex = 0;
|
|||||||
std::array<std::string, MAX_STUBS> stubDlls;
|
std::array<std::string, MAX_STUBS> stubDlls;
|
||||||
std::array<std::string, MAX_STUBS> stubFuncNames;
|
std::array<std::string, MAX_STUBS> stubFuncNames;
|
||||||
std::unordered_map<std::string, StubFuncType> stubCache;
|
std::unordered_map<std::string, StubFuncType> stubCache;
|
||||||
|
std::unordered_map<HANDLE, std::shared_ptr<wibo::ModuleInfo>> g_modules;
|
||||||
|
HANDLE g_nextStubHandle = 1;
|
||||||
|
|
||||||
std::string makeStubKey(const char *dllName, const char *funcName) {
|
std::string makeStubKey(const char *dllName, const char *funcName) {
|
||||||
std::string key;
|
std::string key;
|
||||||
@@ -85,11 +146,6 @@ std::string makeStubKey(const char *dllName, const char *funcName) {
|
|||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <size_t Index> void stubThunk() {
|
|
||||||
// Call the appropriate entry trampoline
|
|
||||||
thunk_entry_stubBase(Index);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <size_t... Indices>
|
template <size_t... Indices>
|
||||||
constexpr std::array<void (*)(void), sizeof...(Indices)> makeStubTable(std::index_sequence<Indices...>) {
|
constexpr std::array<void (*)(void), sizeof...(Indices)> makeStubTable(std::index_sequence<Indices...>) {
|
||||||
return {{stubThunk<Indices>...}};
|
return {{stubThunk<Indices>...}};
|
||||||
@@ -162,8 +218,11 @@ LockedRegistry registry() {
|
|||||||
if (!reg.initialized) {
|
if (!reg.initialized) {
|
||||||
reg.initialized = true;
|
reg.initialized = true;
|
||||||
const wibo::ModuleStub *builtins[] = {
|
const wibo::ModuleStub *builtins[] = {
|
||||||
&lib_advapi32, &lib_bcrypt, &lib_crt, &lib_kernel32, &lib_lmgr, &lib_mscoree, &lib_msvcrt,
|
&lib_advapi32, &lib_bcrypt, /*&lib_crt,*/ &lib_kernel32,
|
||||||
&lib_ntdll, &lib_ole32, &lib_rpcrt4, &lib_user32, &lib_vcruntime, &lib_version, nullptr,
|
&lib_lmgr, &lib_mscoree, /*&lib_msvcrt,*/
|
||||||
|
&lib_ntdll, &lib_ole32, &lib_rpcrt4,
|
||||||
|
&lib_user32, &lib_vcruntime, &lib_version,
|
||||||
|
nullptr,
|
||||||
};
|
};
|
||||||
for (const wibo::ModuleStub **module = builtins; *module; ++module) {
|
for (const wibo::ModuleStub **module = builtins; *module; ++module) {
|
||||||
registerBuiltinModule(reg, *module);
|
registerBuiltinModule(reg, *module);
|
||||||
@@ -204,11 +263,11 @@ struct ParsedModuleName {
|
|||||||
bool endsWithDot = false;
|
bool endsWithDot = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
ParsedModuleName parseModuleName(const std::string &name) {
|
ParsedModuleName parseModuleName(std::string_view name) {
|
||||||
ParsedModuleName parsed;
|
ParsedModuleName parsed;
|
||||||
parsed.original = name;
|
parsed.original = name;
|
||||||
parsed.base = name;
|
parsed.base = name;
|
||||||
std::string sanitized = name;
|
std::string sanitized{name};
|
||||||
std::replace(sanitized.begin(), sanitized.end(), '/', '\\');
|
std::replace(sanitized.begin(), sanitized.end(), '/', '\\');
|
||||||
auto sep = sanitized.find_last_of('\\');
|
auto sep = sanitized.find_last_of('\\');
|
||||||
if (sep != std::string::npos) {
|
if (sep != std::string::npos) {
|
||||||
@@ -282,19 +341,20 @@ bool allocateModuleTlsForThread(wibo::ModuleInfo &module, TEB *tib) {
|
|||||||
if (info.threadAllocations.find(tib) != info.threadAllocations.end()) {
|
if (info.threadAllocations.find(tib) != info.threadAllocations.end()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
void *block = nullptr;
|
GUEST_PTR block = GUEST_NULL;
|
||||||
const size_t allocationSize = info.allocationSize;
|
const size_t allocationSize = info.allocationSize;
|
||||||
if (allocationSize > 0) {
|
if (allocationSize > 0) {
|
||||||
block = wibo::heap::guestMalloc(allocationSize);
|
void *ptr = wibo::heap::guestMalloc(allocationSize);
|
||||||
if (!block) {
|
if (!ptr) {
|
||||||
DEBUG_LOG(" allocateModuleTlsForThread: failed to allocate %zu bytes for %s\n", allocationSize,
|
DEBUG_LOG(" allocateModuleTlsForThread: failed to allocate %zu bytes for %s\n", allocationSize,
|
||||||
module.originalName.c_str());
|
module.originalName.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
std::memset(block, 0, allocationSize);
|
std::memset(ptr, 0, allocationSize);
|
||||||
if (info.templateData && info.templateSize > 0) {
|
if (info.templateData && info.templateSize > 0) {
|
||||||
std::memcpy(block, info.templateData, info.templateSize);
|
std::memcpy(ptr, info.templateData, info.templateSize);
|
||||||
}
|
}
|
||||||
|
block = toGuestPtr(ptr);
|
||||||
}
|
}
|
||||||
info.threadAllocations.emplace(tib, block);
|
info.threadAllocations.emplace(tib, block);
|
||||||
if (!wibo::tls::setValue(tib, info.index, block)) {
|
if (!wibo::tls::setValue(tib, info.index, block)) {
|
||||||
@@ -322,10 +382,10 @@ void freeModuleTlsForThread(wibo::ModuleInfo &module, TEB *tib) {
|
|||||||
if (it == info.threadAllocations.end()) {
|
if (it == info.threadAllocations.end()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
void *block = it->second;
|
GUEST_PTR block = it->second;
|
||||||
info.threadAllocations.erase(it);
|
info.threadAllocations.erase(it);
|
||||||
if (wibo::tls::getValue(tib, info.index) == block) {
|
if (wibo::tls::getValue(tib, info.index) == block) {
|
||||||
if (!wibo::tls::setValue(tib, info.index, nullptr)) {
|
if (!wibo::tls::setValue(tib, info.index, GUEST_NULL)) {
|
||||||
DEBUG_LOG(" freeModuleTlsForThread: failed to clear TLS pointer for %s (index %u)\n",
|
DEBUG_LOG(" freeModuleTlsForThread: failed to clear TLS pointer for %s (index %u)\n",
|
||||||
module.originalName.c_str(), info.index);
|
module.originalName.c_str(), info.index);
|
||||||
}
|
}
|
||||||
@@ -334,7 +394,7 @@ void freeModuleTlsForThread(wibo::ModuleInfo &module, TEB *tib) {
|
|||||||
wibo::tls::clearModulePointer(tib, info.loaderIndex);
|
wibo::tls::clearModulePointer(tib, info.loaderIndex);
|
||||||
}
|
}
|
||||||
if (block) {
|
if (block) {
|
||||||
std::free(block);
|
wibo::heap::guestFree(fromGuestPtr(block));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,7 +406,7 @@ void runModuleTlsCallbacks(wibo::ModuleInfo &module, DWORD reason) {
|
|||||||
if (!callback) {
|
if (!callback) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
call_PIMAGE_TLS_CALLBACK(callback, module.handle, reason, nullptr);
|
call_PIMAGE_TLS_CALLBACK(callback, reinterpret_cast<PVOID>(module.handle), reason, nullptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -502,7 +562,9 @@ void registerBuiltinModule(ModuleRegistry ®, const wibo::ModuleStub *module)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
wibo::ModulePtr entry = std::make_shared<wibo::ModuleInfo>();
|
wibo::ModulePtr entry = std::make_shared<wibo::ModuleInfo>();
|
||||||
entry->handle = entry.get();
|
HANDLE handle = g_nextStubHandle++;
|
||||||
|
g_modules[handle] = entry;
|
||||||
|
entry->handle = handle;
|
||||||
entry->moduleStub = module;
|
entry->moduleStub = module;
|
||||||
entry->refCount = UINT_MAX;
|
entry->refCount = UINT_MAX;
|
||||||
entry->originalName = module->names[0] ? module->names[0] : "";
|
entry->originalName = module->names[0] ? module->names[0] : "";
|
||||||
@@ -570,12 +632,10 @@ BOOL callDllMain(wibo::ModuleInfo &info, DWORD reason, LPVOID reserved) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_LOG(" callDllMain: invoking DllMain(%p, %u, %p) for %s\n",
|
DEBUG_LOG(" callDllMain: invoking DllMain(%p, %u, %p) for %s\n", toGuestPtr(info.executable->imageBase),
|
||||||
reinterpret_cast<HMODULE>(info.executable->imageBase), callReason, callReserved,
|
callReason, callReserved, info.normalizedName.c_str());
|
||||||
info.normalizedName.c_str());
|
|
||||||
|
|
||||||
BOOL result =
|
BOOL result = call_DllEntryProc(dllMain, toGuestPtr(info.executable->imageBase), callReason, callReserved);
|
||||||
call_DllEntryProc(dllMain, reinterpret_cast<HMODULE>(info.executable->imageBase), callReason, callReserved);
|
|
||||||
DEBUG_LOG(" callDllMain: %s DllMain returned %d\n", info.normalizedName.c_str(), result);
|
DEBUG_LOG(" callDllMain: %s DllMain returned %d\n", info.normalizedName.c_str(), result);
|
||||||
return result;
|
return result;
|
||||||
};
|
};
|
||||||
@@ -739,7 +799,7 @@ ModuleInfo *registerProcessModule(std::unique_ptr<Executable> executable, std::f
|
|||||||
std::string normalizedName = normalizedBaseKey(parsed);
|
std::string normalizedName = normalizedBaseKey(parsed);
|
||||||
|
|
||||||
ModulePtr info = std::make_unique<ModuleInfo>();
|
ModulePtr info = std::make_unique<ModuleInfo>();
|
||||||
info->handle = executable->imageBase; // Use image base as handle for main module
|
info->handle = toGuestPtr(executable->imageBase); // Use image base as handle for main module
|
||||||
info->moduleStub = nullptr;
|
info->moduleStub = nullptr;
|
||||||
info->originalName = std::move(originalName);
|
info->originalName = std::move(originalName);
|
||||||
info->normalizedName = std::move(normalizedName);
|
info->normalizedName = std::move(normalizedName);
|
||||||
@@ -825,7 +885,7 @@ ModuleInfo *moduleInfoFromHandle(HMODULE module) {
|
|||||||
if (info->handle == module) {
|
if (info->handle == module) {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
if (info->executable && info->executable->imageBase == module) {
|
if (info->executable && info->executable->imageBase == reinterpret_cast<void *>(module)) {
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -883,7 +943,7 @@ bool initializeModuleTls(ModuleInfo &module) {
|
|||||||
info.callbacks.clear();
|
info.callbacks.clear();
|
||||||
uintptr_t callbacksArray = resolveModuleAddress(exec, tlsDirectory->AddressOfCallBacks);
|
uintptr_t callbacksArray = resolveModuleAddress(exec, tlsDirectory->AddressOfCallBacks);
|
||||||
if (callbacksArray) {
|
if (callbacksArray) {
|
||||||
auto callbackPtr = reinterpret_cast<uintptr_t *>(callbacksArray);
|
auto callbackPtr = reinterpret_cast<GUEST_PTR *>(callbacksArray);
|
||||||
while (callbackPtr && *callbackPtr) {
|
while (callbackPtr && *callbackPtr) {
|
||||||
info.callbacks.push_back(reinterpret_cast<PIMAGE_TLS_CALLBACK>(resolveModuleAddress(exec, *callbackPtr)));
|
info.callbacks.push_back(reinterpret_cast<PIMAGE_TLS_CALLBACK>(resolveModuleAddress(exec, *callbackPtr)));
|
||||||
++callbackPtr;
|
++callbackPtr;
|
||||||
@@ -937,13 +997,13 @@ bool initializeModuleTls(ModuleInfo &module) {
|
|||||||
if (!ctx.success) {
|
if (!ctx.success) {
|
||||||
for (auto &[thread, block] : info.threadAllocations) {
|
for (auto &[thread, block] : info.threadAllocations) {
|
||||||
if (block) {
|
if (block) {
|
||||||
std::free(block);
|
wibo::heap::guestFree(fromGuestPtr(block));
|
||||||
}
|
}
|
||||||
if (info.loaderIndex != tls::kInvalidTlsIndex) {
|
if (info.loaderIndex != tls::kInvalidTlsIndex) {
|
||||||
wibo::tls::clearModulePointer(thread, info.loaderIndex);
|
wibo::tls::clearModulePointer(thread, info.loaderIndex);
|
||||||
}
|
}
|
||||||
if (wibo::tls::getValue(thread, info.index) == block) {
|
if (wibo::tls::getValue(thread, info.index) == block) {
|
||||||
wibo::tls::setValue(thread, info.index, nullptr);
|
wibo::tls::setValue(thread, info.index, GUEST_NULL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info.threadAllocations.clear();
|
info.threadAllocations.clear();
|
||||||
@@ -971,14 +1031,14 @@ void releaseModuleTls(ModuleInfo &module) {
|
|||||||
for (auto &[tib, block] : info.threadAllocations) {
|
for (auto &[tib, block] : info.threadAllocations) {
|
||||||
if (tib) {
|
if (tib) {
|
||||||
if (wibo::tls::getValue(tib, info.index) == block) {
|
if (wibo::tls::getValue(tib, info.index) == block) {
|
||||||
wibo::tls::setValue(tib, info.index, nullptr);
|
wibo::tls::setValue(tib, info.index, GUEST_NULL);
|
||||||
}
|
}
|
||||||
if (info.loaderIndex != tls::kInvalidTlsIndex) {
|
if (info.loaderIndex != tls::kInvalidTlsIndex) {
|
||||||
wibo::tls::clearModulePointer(tib, info.loaderIndex);
|
wibo::tls::clearModulePointer(tib, info.loaderIndex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (block) {
|
if (block) {
|
||||||
std::free(block);
|
wibo::heap::guestFree(fromGuestPtr(block));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
info.threadAllocations.clear();
|
info.threadAllocations.clear();
|
||||||
@@ -1068,18 +1128,9 @@ ModuleInfo *findLoadedModule(const char *name) {
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleInfo *loadModule(const char *dllName) {
|
static ModuleInfo *loadModuleInternal(const std::string &dllName) {
|
||||||
if (!dllName || *dllName == '\0') {
|
|
||||||
kernel32::setLastError(ERROR_INVALID_PARAMETER);
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
std::string requested(dllName);
|
|
||||||
DEBUG_LOG("loadModule(%s)\n", requested.c_str());
|
|
||||||
|
|
||||||
auto reg = registry();
|
auto reg = registry();
|
||||||
|
ParsedModuleName parsed = parseModuleName(dllName);
|
||||||
ParsedModuleName parsed = parseModuleName(requested);
|
|
||||||
|
|
||||||
DWORD diskError = ERROR_SUCCESS;
|
DWORD diskError = ERROR_SUCCESS;
|
||||||
|
|
||||||
auto tryLoadExternal = [&](const std::filesystem::path &path) -> ModuleInfo * {
|
auto tryLoadExternal = [&](const std::filesystem::path &path) -> ModuleInfo * {
|
||||||
@@ -1090,7 +1141,7 @@ ModuleInfo *loadModule(const char *dllName) {
|
|||||||
if (info->refCount != UINT_MAX) {
|
if (info->refCount != UINT_MAX) {
|
||||||
info->refCount++;
|
info->refCount++;
|
||||||
}
|
}
|
||||||
registerExternalModuleAliases(*reg, requested, files::canonicalPath(path), info);
|
registerExternalModuleAliases(*reg, dllName, files::canonicalPath(path), info);
|
||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
reg.lock.unlock();
|
reg.lock.unlock();
|
||||||
@@ -1115,9 +1166,11 @@ ModuleInfo *loadModule(const char *dllName) {
|
|||||||
fclose(file);
|
fclose(file);
|
||||||
|
|
||||||
ModulePtr info = std::make_unique<ModuleInfo>();
|
ModulePtr info = std::make_unique<ModuleInfo>();
|
||||||
info->handle = info.get();
|
HANDLE handle = g_nextStubHandle++;
|
||||||
|
g_modules[handle] = info;
|
||||||
|
info->handle = handle;
|
||||||
info->moduleStub = nullptr;
|
info->moduleStub = nullptr;
|
||||||
info->originalName = requested;
|
info->originalName = dllName;
|
||||||
info->normalizedName = normalizedBaseKey(parsed);
|
info->normalizedName = normalizedBaseKey(parsed);
|
||||||
info->resolvedPath = files::canonicalPath(path);
|
info->resolvedPath = files::canonicalPath(path);
|
||||||
info->executable = std::move(executable);
|
info->executable = std::move(executable);
|
||||||
@@ -1126,7 +1179,7 @@ ModuleInfo *loadModule(const char *dllName) {
|
|||||||
reg.lock.lock();
|
reg.lock.lock();
|
||||||
ModuleInfo *raw = info.get();
|
ModuleInfo *raw = info.get();
|
||||||
reg->modulesByKey[key] = std::move(info);
|
reg->modulesByKey[key] = std::move(info);
|
||||||
registerExternalModuleAliases(*reg, requested, raw->resolvedPath, raw);
|
registerExternalModuleAliases(*reg, dllName, raw->resolvedPath, raw);
|
||||||
reg.lock.unlock();
|
reg.lock.unlock();
|
||||||
ensureExportsInitialized(*raw);
|
ensureExportsInitialized(*raw);
|
||||||
if (!raw->executable->resolveImports()) {
|
if (!raw->executable->resolveImports()) {
|
||||||
@@ -1165,7 +1218,7 @@ ModuleInfo *loadModule(const char *dllName) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto resolveAndLoadExternal = [&]() -> ModuleInfo * {
|
auto resolveAndLoadExternal = [&]() -> ModuleInfo * {
|
||||||
auto resolvedPath = resolveModuleOnDisk(*reg, requested, false);
|
auto resolvedPath = resolveModuleOnDisk(*reg, dllName, false);
|
||||||
if (!resolvedPath) {
|
if (!resolvedPath) {
|
||||||
DEBUG_LOG(" module not found on disk\n");
|
DEBUG_LOG(" module not found on disk\n");
|
||||||
diskError = ERROR_MOD_NOT_FOUND;
|
diskError = ERROR_MOD_NOT_FOUND;
|
||||||
@@ -1177,7 +1230,7 @@ ModuleInfo *loadModule(const char *dllName) {
|
|||||||
std::string alias = normalizedBaseKey(parsed);
|
std::string alias = normalizedBaseKey(parsed);
|
||||||
ModuleInfo *existing = findByAlias(*reg, alias);
|
ModuleInfo *existing = findByAlias(*reg, alias);
|
||||||
if (!existing) {
|
if (!existing) {
|
||||||
existing = findByAlias(*reg, normalizeAlias(requested));
|
existing = findByAlias(*reg, normalizeAlias(dllName));
|
||||||
}
|
}
|
||||||
if (existing) {
|
if (existing) {
|
||||||
DEBUG_LOG(" found existing module alias %s (builtin=%d)\n", alias.c_str(), existing->moduleStub != nullptr);
|
DEBUG_LOG(" found existing module alias %s (builtin=%d)\n", alias.c_str(), existing->moduleStub != nullptr);
|
||||||
@@ -1188,10 +1241,10 @@ ModuleInfo *loadModule(const char *dllName) {
|
|||||||
DEBUG_LOG(" returning existing external module %s\n", existing->originalName.c_str());
|
DEBUG_LOG(" returning existing external module %s\n", existing->originalName.c_str());
|
||||||
return existing;
|
return existing;
|
||||||
}
|
}
|
||||||
bool pinned = reg->pinnedModules.count(existing) != 0;
|
bool pinned = reg->pinnedModules.contains(existing);
|
||||||
if (!pinned) {
|
if (!pinned) {
|
||||||
if (ModuleInfo *external = resolveAndLoadExternal()) {
|
if (ModuleInfo *external = resolveAndLoadExternal()) {
|
||||||
DEBUG_LOG(" replaced builtin module %s with external copy\n", requested.c_str());
|
DEBUG_LOG(" replaced builtin module %s with external copy\n", dllName.c_str());
|
||||||
return external;
|
return external;
|
||||||
} else if (diskError != ERROR_MOD_NOT_FOUND) {
|
} else if (diskError != ERROR_MOD_NOT_FOUND) {
|
||||||
kernel32::setLastError(diskError);
|
kernel32::setLastError(diskError);
|
||||||
@@ -1203,7 +1256,7 @@ ModuleInfo *loadModule(const char *dllName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ModuleInfo *external = resolveAndLoadExternal()) {
|
if (ModuleInfo *external = resolveAndLoadExternal()) {
|
||||||
DEBUG_LOG(" loaded external module %s\n", requested.c_str());
|
DEBUG_LOG(" loaded external module %s\n", dllName.c_str());
|
||||||
return external;
|
return external;
|
||||||
} else if (diskError != ERROR_MOD_NOT_FOUND) {
|
} else if (diskError != ERROR_MOD_NOT_FOUND) {
|
||||||
kernel32::setLastError(diskError);
|
kernel32::setLastError(diskError);
|
||||||
@@ -1217,7 +1270,7 @@ ModuleInfo *loadModule(const char *dllName) {
|
|||||||
builtin = builtinIt->second;
|
builtin = builtinIt->second;
|
||||||
}
|
}
|
||||||
if (!builtin) {
|
if (!builtin) {
|
||||||
builtinIt = reg->builtinAliasMap.find(normalizeAlias(requested));
|
builtinIt = reg->builtinAliasMap.find(normalizeAlias(dllName));
|
||||||
if (builtinIt != reg->builtinAliasMap.end()) {
|
if (builtinIt != reg->builtinAliasMap.end()) {
|
||||||
builtin = builtinIt->second;
|
builtin = builtinIt->second;
|
||||||
}
|
}
|
||||||
@@ -1231,6 +1284,46 @@ ModuleInfo *loadModule(const char *dllName) {
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ModuleInfo *loadModule(const char* dllName) {
|
||||||
|
if (!dllName || *dllName == '\0') {
|
||||||
|
kernel32::setLastError(ERROR_INVALID_PARAMETER);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
DEBUG_LOG("loadModule(%s)\n", dllName);
|
||||||
|
std::string_view requested{dllName};
|
||||||
|
|
||||||
|
const auto parsed = parseModuleName(requested);
|
||||||
|
std::string normalized = normalizedBaseKey(parsed);
|
||||||
|
|
||||||
|
for (auto& [alias, module] : kApiSet) {
|
||||||
|
if (alias == normalized) {
|
||||||
|
DEBUG_LOG(" resolved api set %s -> %s\n", alias.data(), module.data());
|
||||||
|
requested = module;
|
||||||
|
normalized = module;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DWORD lastError = kernel32::getLastError();
|
||||||
|
if (auto* info = loadModuleInternal(std::string{requested})) {
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
if (kernel32::getLastError() != ERROR_MOD_NOT_FOUND) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel32::setLastError(lastError);
|
||||||
|
for (auto& [module, fallback] : kFallbacks) {
|
||||||
|
if (module == normalized) {
|
||||||
|
DEBUG_LOG(" trying fallback %s -> %s\n", module.data(), fallback.data());
|
||||||
|
return loadModuleInternal(std::string{fallback});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel32::setLastError(ERROR_MOD_NOT_FOUND);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
void freeModule(ModuleInfo *info) {
|
void freeModule(ModuleInfo *info) {
|
||||||
auto reg = registry();
|
auto reg = registry();
|
||||||
if (!info || info->refCount == UINT_MAX) {
|
if (!info || info->refCount == UINT_MAX) {
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "entry.h"
|
#include "entry.h"
|
||||||
#include "msvcrt.h"
|
#include "msvcrt.h"
|
||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@@ -39,8 +40,7 @@ class Executable {
|
|||||||
bool findResource(const ResourceIdentifier &type, const ResourceIdentifier &name, std::optional<uint16_t> language,
|
bool findResource(const ResourceIdentifier &type, const ResourceIdentifier &name, std::optional<uint16_t> language,
|
||||||
ResourceLocation &out) const;
|
ResourceLocation &out) const;
|
||||||
|
|
||||||
template <typename T> T *fromRVA(uintptr_t rva) const { return (T *)(rva + (uint8_t *)imageBase); }
|
template <typename T> T *fromRVA(uint32_t rva) const { return (T *)(rva + (uint8_t *)imageBase); }
|
||||||
template <typename T> T *fromRVA(T *rva) const { return fromRVA<T>((uintptr_t)rva); }
|
|
||||||
|
|
||||||
void *imageBase = nullptr;
|
void *imageBase = nullptr;
|
||||||
size_t imageSize = 0;
|
size_t imageSize = 0;
|
||||||
@@ -77,7 +77,7 @@ struct ModuleTlsInfo {
|
|||||||
uint32_t characteristics = 0;
|
uint32_t characteristics = 0;
|
||||||
size_t allocationSize = 0;
|
size_t allocationSize = 0;
|
||||||
std::vector<PIMAGE_TLS_CALLBACK> callbacks;
|
std::vector<PIMAGE_TLS_CALLBACK> callbacks;
|
||||||
std::unordered_map<TEB *, void *> threadAllocations;
|
std::unordered_map<TEB *, GUEST_PTR> threadAllocations;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ModuleInfo {
|
struct ModuleInfo {
|
||||||
@@ -140,8 +140,8 @@ ModuleInfo *moduleInfoFromAddress(void *addr);
|
|||||||
* otherwise it will be a pointer to a `wibo::ModuleInfo`.
|
* otherwise it will be a pointer to a `wibo::ModuleInfo`.
|
||||||
*/
|
*/
|
||||||
inline bool isMainModule(HMODULE hModule) {
|
inline bool isMainModule(HMODULE hModule) {
|
||||||
return hModule == nullptr || hModule == reinterpret_cast<HMODULE>(mainModule) ||
|
return hModule == NO_HANDLE || (mainModule && mainModule->executable &&
|
||||||
(mainModule && mainModule->executable && hModule == mainModule->executable->imageBase);
|
reinterpret_cast<void *>(hModule) == mainModule->executable->imageBase);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace wibo
|
} // namespace wibo
|
||||||
|
|||||||
74
src/setup.S
Normal file
74
src/setup.S
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "macros.S"
|
||||||
|
.section .note.GNU-stack, "", @progbits
|
||||||
|
.text
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
|
||||||
|
# int x86_64_thread_setup(int entry_number, void *teb)
|
||||||
|
.globl x86_64_thread_setup
|
||||||
|
.type x86_64_thread_setup, @function
|
||||||
|
x86_64_thread_setup:
|
||||||
|
push rbx # save rbx
|
||||||
|
mov r8, rsp # save host stack
|
||||||
|
rdfsbase r9 # read host FS base
|
||||||
|
mov rdx, qword ptr [rsi+TEB_SP] # fetch guest stack
|
||||||
|
LJMP32 # far jump into 32-bit code
|
||||||
|
mov ax, 0x2b # user data segment (Linux)
|
||||||
|
mov ds, ax # setup data segment
|
||||||
|
mov es, ax # setup extra segment
|
||||||
|
mov esp, edx # switch to guest stack
|
||||||
|
sub esp, 0x10 # sizeof(user_desc)
|
||||||
|
mov dword ptr [esp], edi # entry_number (arg 0)
|
||||||
|
mov dword ptr [esp+4], esi # base_addr (arg 1)
|
||||||
|
mov dword ptr [esp+8], 0xffff # limit
|
||||||
|
mov dword ptr [esp+12], 0x41 # seg_32bit | usable
|
||||||
|
mov ebx, esp # &user_desc
|
||||||
|
mov eax, 0xf3 # SYS_set_thread_area
|
||||||
|
int 0x80 # syscall
|
||||||
|
test eax, eax # check for error
|
||||||
|
jnz 1f # skip selector setup
|
||||||
|
mov eax, dword ptr [esp] # entry_number
|
||||||
|
cmp eax, -1 # check for invalid entry_number
|
||||||
|
jz 2f # skip selector setup
|
||||||
|
lea ebx, [eax*8+3] # create selector
|
||||||
|
mov fs, bx # setup fs segment
|
||||||
|
mov word ptr [esi+TEB_FS_SEL], bx # save selector
|
||||||
|
jmp 2f # skip error handling
|
||||||
|
1:
|
||||||
|
mov eax, -1 # return -1
|
||||||
|
2:
|
||||||
|
add esp, 0x10 # cleanup stack
|
||||||
|
LJMP64 # far jump into 64-bit code
|
||||||
|
cdqe # sign-extend eax to rax
|
||||||
|
mov rsp, r8 # switch to host stack
|
||||||
|
wrfsbase r9 # restore host FS base
|
||||||
|
pop rbx # restore rbx
|
||||||
|
ret
|
||||||
|
.size x86_64_thread_setup, .-x86_64_thread_setup
|
||||||
|
|
||||||
|
#endif // __x86_64__
|
||||||
|
|
||||||
|
.altmacro
|
||||||
|
.code32
|
||||||
|
|
||||||
|
.macro stubThunkX number
|
||||||
|
#ifdef __x86_64__
|
||||||
|
.globl _Z9stubThunkILm\()\number\()EEvv
|
||||||
|
.type _Z9stubThunkILm\()\number\()EEvv, @function
|
||||||
|
_Z9stubThunkILm\()\number\()EEvv:
|
||||||
|
#else
|
||||||
|
.globl _Z9stubThunkILj\()\number\()EEvv
|
||||||
|
.type _Z9stubThunkILj\()\number\()EEvv, @function
|
||||||
|
_Z9stubThunkILj\()\number\()EEvv:
|
||||||
|
#endif
|
||||||
|
pop eax
|
||||||
|
push \number
|
||||||
|
push eax
|
||||||
|
jmp thunk_entry_stubBase
|
||||||
|
.endm
|
||||||
|
|
||||||
|
.set i, 0
|
||||||
|
.rept 256
|
||||||
|
stubThunkX %i
|
||||||
|
.set i, i+1
|
||||||
|
.endr
|
||||||
13
src/setup.h
Normal file
13
src/setup.h
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
int x86_64_thread_setup(int entry_number, void *teb);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
40
src/tls.cpp
40
src/tls.cpp
@@ -1,5 +1,7 @@
|
|||||||
#include "tls.h"
|
#include "tls.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
#include "heap.h"
|
||||||
|
#include "types.h"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
@@ -20,7 +22,7 @@ size_t g_expansionCapacity = 0;
|
|||||||
|
|
||||||
struct TlsArray {
|
struct TlsArray {
|
||||||
size_t capacity;
|
size_t capacity;
|
||||||
void *slots[];
|
GUEST_PTR slots[];
|
||||||
};
|
};
|
||||||
|
|
||||||
std::unordered_map<TEB *, TlsArray *> g_moduleArrays;
|
std::unordered_map<TEB *, TlsArray *> g_moduleArrays;
|
||||||
@@ -31,8 +33,8 @@ TlsArray *allocateTlsArray(size_t capacity) {
|
|||||||
if (capacity == 0 || capacity > kMaxExpansionSlots) {
|
if (capacity == 0 || capacity > kMaxExpansionSlots) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
const size_t bytes = sizeof(TlsArray) + capacity * sizeof(void *);
|
const size_t bytes = sizeof(TlsArray) + capacity * sizeof(GUEST_PTR);
|
||||||
auto *arr = static_cast<TlsArray *>(std::calloc(1, bytes));
|
auto *arr = static_cast<TlsArray *>(wibo::heap::guestCalloc(1, bytes));
|
||||||
if (!arr) {
|
if (!arr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -40,7 +42,7 @@ TlsArray *allocateTlsArray(size_t capacity) {
|
|||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline TlsArray *arrayFromSlots(void *slots) {
|
inline TlsArray *arrayFromSlots(GUEST_PTR slots) {
|
||||||
return slots ? reinterpret_cast<TlsArray *>(reinterpret_cast<uint8_t *>(slots) - offsetof(TlsArray, slots))
|
return slots ? reinterpret_cast<TlsArray *>(reinterpret_cast<uint8_t *>(slots) - offsetof(TlsArray, slots))
|
||||||
: nullptr;
|
: nullptr;
|
||||||
}
|
}
|
||||||
@@ -56,7 +58,7 @@ void setExpansionArray(TEB *tib, TlsArray *arr) {
|
|||||||
if (!tib) {
|
if (!tib) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
tib->TlsExpansionSlots = arr ? arr->slots : nullptr;
|
tib->TlsExpansionSlots = arr ? toGuestPtr(arr->slots) : GUEST_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t chooseCapacity(size_t current, size_t required) {
|
size_t chooseCapacity(size_t current, size_t required) {
|
||||||
@@ -202,7 +204,7 @@ bool ensureModuleArrayCapacityLocked(size_t required) {
|
|||||||
}
|
}
|
||||||
for (auto &entry : pending) {
|
for (auto &entry : pending) {
|
||||||
g_moduleArrays[entry.tib] = entry.newArray;
|
g_moduleArrays[entry.tib] = entry.newArray;
|
||||||
entry.tib->ThreadLocalStoragePointer = entry.newArray->slots;
|
entry.tib->ThreadLocalStoragePointer = toGuestPtr(entry.newArray->slots);
|
||||||
if (entry.oldArray) {
|
if (entry.oldArray) {
|
||||||
queueOldModuleArray(entry.tib, entry.oldArray);
|
queueOldModuleArray(entry.tib, entry.oldArray);
|
||||||
}
|
}
|
||||||
@@ -214,7 +216,7 @@ bool ensureModuleArrayCapacityLocked(size_t required) {
|
|||||||
void zeroSlotForAllTibs(size_t index) {
|
void zeroSlotForAllTibs(size_t index) {
|
||||||
if (index < kTlsSlotCount) {
|
if (index < kTlsSlotCount) {
|
||||||
for (TEB *tib : g_activeTibs) {
|
for (TEB *tib : g_activeTibs) {
|
||||||
tib->TlsSlots[index] = nullptr;
|
tib->TlsSlots[index] = GUEST_NULL;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -224,7 +226,7 @@ void zeroSlotForAllTibs(size_t index) {
|
|||||||
if (!arr || expansionIndex >= arr->capacity) {
|
if (!arr || expansionIndex >= arr->capacity) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
arr->slots[expansionIndex] = nullptr;
|
arr->slots[expansionIndex] = GUEST_NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -272,7 +274,7 @@ void cleanupTib(TEB *tib) {
|
|||||||
}
|
}
|
||||||
g_moduleGarbage.erase(garbageIt);
|
g_moduleGarbage.erase(garbageIt);
|
||||||
}
|
}
|
||||||
tib->ThreadLocalStoragePointer = nullptr;
|
tib->ThreadLocalStoragePointer = GUEST_NULL;
|
||||||
auto it = std::find(g_activeTibs.begin(), g_activeTibs.end(), tib);
|
auto it = std::find(g_activeTibs.begin(), g_activeTibs.end(), tib);
|
||||||
if (it != g_activeTibs.end()) {
|
if (it != g_activeTibs.end()) {
|
||||||
g_activeTibs.erase(it);
|
g_activeTibs.erase(it);
|
||||||
@@ -316,9 +318,9 @@ bool isSlotAllocated(DWORD index) {
|
|||||||
return index < wibo::tls::kTlsMaxSlotCount && g_slotUsed[index];
|
return index < wibo::tls::kTlsMaxSlotCount && g_slotUsed[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
void *getValue(TEB *tib, DWORD index) {
|
GUEST_PTR getValue(TEB *tib, DWORD index) {
|
||||||
if (!tib || index >= static_cast<DWORD>(wibo::tls::kTlsMaxSlotCount)) {
|
if (!tib || index >= static_cast<DWORD>(wibo::tls::kTlsMaxSlotCount)) {
|
||||||
return nullptr;
|
return GUEST_NULL;
|
||||||
}
|
}
|
||||||
if (index < static_cast<DWORD>(kTlsSlotCount)) {
|
if (index < static_cast<DWORD>(kTlsSlotCount)) {
|
||||||
return tib->TlsSlots[index];
|
return tib->TlsSlots[index];
|
||||||
@@ -326,16 +328,16 @@ void *getValue(TEB *tib, DWORD index) {
|
|||||||
std::lock_guard lock(g_tlsMutex);
|
std::lock_guard lock(g_tlsMutex);
|
||||||
auto *arr = getExpansionArray(tib);
|
auto *arr = getExpansionArray(tib);
|
||||||
if (!arr) {
|
if (!arr) {
|
||||||
return nullptr;
|
return GUEST_NULL;
|
||||||
}
|
}
|
||||||
size_t expansionIndex = static_cast<size_t>(index) - kTlsSlotCount;
|
size_t expansionIndex = static_cast<size_t>(index) - kTlsSlotCount;
|
||||||
if (expansionIndex >= arr->capacity) {
|
if (expansionIndex >= arr->capacity) {
|
||||||
return nullptr;
|
return GUEST_NULL;
|
||||||
}
|
}
|
||||||
return arr->slots[expansionIndex];
|
return arr->slots[expansionIndex];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setValue(TEB *tib, DWORD index, void *value) {
|
bool setValue(TEB *tib, DWORD index, GUEST_PTR value) {
|
||||||
if (!tib || index >= static_cast<DWORD>(wibo::tls::kTlsMaxSlotCount)) {
|
if (!tib || index >= static_cast<DWORD>(wibo::tls::kTlsMaxSlotCount)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -357,9 +359,9 @@ bool setValue(TEB *tib, DWORD index, void *value) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *getValue(DWORD index) { return getValue(currentThreadTeb, index); }
|
GUEST_PTR getValue(DWORD index) { return getValue(currentThreadTeb, index); }
|
||||||
|
|
||||||
bool setValue(DWORD index, void *value) { return setValue(currentThreadTeb, index, value); }
|
bool setValue(DWORD index, GUEST_PTR value) { return setValue(currentThreadTeb, index, value); }
|
||||||
|
|
||||||
void forEachTib(void (*callback)(TEB *, void *), void *context) {
|
void forEachTib(void (*callback)(TEB *, void *), void *context) {
|
||||||
if (!callback) {
|
if (!callback) {
|
||||||
@@ -380,7 +382,7 @@ bool ensureModulePointerCapacity(size_t capacity) {
|
|||||||
return ensureModuleArrayCapacityLocked(capacity);
|
return ensureModuleArrayCapacityLocked(capacity);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool setModulePointer(TEB *tib, size_t index, void *value) {
|
bool setModulePointer(TEB *tib, size_t index, GUEST_PTR value) {
|
||||||
if (!tib) {
|
if (!tib) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -393,7 +395,7 @@ bool setModulePointer(TEB *tib, size_t index, void *value) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
array->slots[index] = value;
|
array->slots[index] = value;
|
||||||
tib->ThreadLocalStoragePointer = array->slots;
|
tib->ThreadLocalStoragePointer = toGuestPtr(array->slots);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -406,7 +408,7 @@ void clearModulePointer(TEB *tib, size_t index) {
|
|||||||
if (!array || index >= array->capacity) {
|
if (!array || index >= array->capacity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
array->slots[index] = nullptr;
|
array->slots[index] = GUEST_NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace wibo::tls
|
} // namespace wibo::tls
|
||||||
|
|||||||
10
src/tls.h
10
src/tls.h
@@ -13,17 +13,17 @@ void cleanupTib(TEB *tib);
|
|||||||
void forEachTib(void (*callback)(TEB *, void *), void *context);
|
void forEachTib(void (*callback)(TEB *, void *), void *context);
|
||||||
|
|
||||||
bool ensureModulePointerCapacity(size_t capacity);
|
bool ensureModulePointerCapacity(size_t capacity);
|
||||||
bool setModulePointer(TEB *tib, size_t index, void *value);
|
bool setModulePointer(TEB *tib, size_t index, GUEST_PTR value);
|
||||||
void clearModulePointer(TEB *tib, size_t index);
|
void clearModulePointer(TEB *tib, size_t index);
|
||||||
|
|
||||||
DWORD reserveSlot();
|
DWORD reserveSlot();
|
||||||
bool releaseSlot(DWORD index);
|
bool releaseSlot(DWORD index);
|
||||||
bool isSlotAllocated(DWORD index);
|
bool isSlotAllocated(DWORD index);
|
||||||
|
|
||||||
void *getValue(TEB *tib, DWORD index);
|
GUEST_PTR getValue(TEB *tib, DWORD index);
|
||||||
bool setValue(TEB *tib, DWORD index, void *value);
|
bool setValue(TEB *tib, DWORD index, GUEST_PTR value);
|
||||||
|
|
||||||
void *getValue(DWORD index);
|
GUEST_PTR getValue(DWORD index);
|
||||||
bool setValue(DWORD index, void *value);
|
bool setValue(DWORD index, GUEST_PTR value);
|
||||||
|
|
||||||
} // namespace wibo::tls
|
} // namespace wibo::tls
|
||||||
|
|||||||
184
src/types.h
184
src/types.h
@@ -4,11 +4,6 @@
|
|||||||
#define va_list __builtin_va_list
|
#define va_list __builtin_va_list
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// On Windows, the incoming stack is aligned to a 4 byte boundary.
|
|
||||||
// force_align_arg_pointer will realign the stack to match GCC's 16 byte alignment.
|
|
||||||
#define WIN_ENTRY __attribute__((cdecl, force_align_arg_pointer))
|
|
||||||
#define WIN_FUNC __attribute__((stdcall, force_align_arg_pointer))
|
|
||||||
|
|
||||||
// Annotation macros for code generation
|
// Annotation macros for code generation
|
||||||
#ifdef WIBO_CODEGEN
|
#ifdef WIBO_CODEGEN
|
||||||
#define WIBO_ANNOTATE(x) __attribute__((annotate(x)))
|
#define WIBO_ANNOTATE(x) __attribute__((annotate(x)))
|
||||||
@@ -32,19 +27,41 @@
|
|||||||
#define _CC_STDCALL WIBO_ANNOTATE("CC:stdcall")
|
#define _CC_STDCALL WIBO_ANNOTATE("CC:stdcall")
|
||||||
|
|
||||||
// Instructs codegen to convert between calling conventions
|
// Instructs codegen to convert between calling conventions
|
||||||
|
#ifdef __x86_64__
|
||||||
|
#define WINAPI _CC_STDCALL
|
||||||
|
#define CDECL _CC_CDECL
|
||||||
|
#define CDECL_NO_CONV _CC_CDECL __attribute__((force_align_arg_pointer))
|
||||||
|
#else
|
||||||
#define WINAPI _CC_STDCALL __attribute__((fastcall))
|
#define WINAPI _CC_STDCALL __attribute__((fastcall))
|
||||||
#define CDECL _CC_CDECL __attribute__((fastcall))
|
#define CDECL _CC_CDECL __attribute__((fastcall))
|
||||||
#define CDECL_NO_CONV _CC_CDECL __attribute__((cdecl, force_align_arg_pointer))
|
#define CDECL_NO_CONV _CC_CDECL __attribute__((cdecl, force_align_arg_pointer))
|
||||||
|
#endif
|
||||||
|
|
||||||
// Used for host-to-guest calls
|
// Used for host-to-guest calls
|
||||||
#define GUEST_STDCALL __attribute__((stdcall))
|
#define GUEST_STDCALL __attribute__((stdcall))
|
||||||
|
|
||||||
|
typedef unsigned int GUEST_PTR;
|
||||||
|
constexpr GUEST_PTR GUEST_NULL = 0;
|
||||||
|
|
||||||
|
#ifdef __x86_64__
|
||||||
|
inline GUEST_PTR toGuestPtr(const void *addr) {
|
||||||
|
unsigned long long addr64 = reinterpret_cast<unsigned long long>(addr);
|
||||||
|
if (addr64 > 0xFFFFFFFF)
|
||||||
|
__builtin_unreachable();
|
||||||
|
return static_cast<GUEST_PTR>(addr64);
|
||||||
|
}
|
||||||
|
inline void *fromGuestPtr(GUEST_PTR addr) { return reinterpret_cast<void *>(addr); }
|
||||||
|
#else
|
||||||
|
inline GUEST_PTR toGuestPtr(const void *addr) { return static_cast<GUEST_PTR>(reinterpret_cast<unsigned long>(addr)); }
|
||||||
|
inline void *fromGuestPtr(GUEST_PTR addr) { return reinterpret_cast<void *>(addr); }
|
||||||
|
#endif
|
||||||
|
|
||||||
using VOID = void;
|
using VOID = void;
|
||||||
using HANDLE = VOID *;
|
using HANDLE = int;
|
||||||
using HMODULE = VOID *;
|
using HMODULE = HANDLE;
|
||||||
using HGLOBAL = HANDLE;
|
using HGLOBAL = GUEST_PTR;
|
||||||
using HLOCAL = HANDLE;
|
using HLOCAL = GUEST_PTR;
|
||||||
using HRSRC = HANDLE;
|
using HRSRC = GUEST_PTR;
|
||||||
using HINSTANCE = HANDLE;
|
using HINSTANCE = HANDLE;
|
||||||
using LPHANDLE = HANDLE *;
|
using LPHANDLE = HANDLE *;
|
||||||
using PHANDLE = HANDLE *;
|
using PHANDLE = HANDLE *;
|
||||||
@@ -66,12 +83,9 @@ using ULONG = unsigned int;
|
|||||||
using PULONG = ULONG *;
|
using PULONG = ULONG *;
|
||||||
using LONGLONG = long long;
|
using LONGLONG = long long;
|
||||||
using ULONGLONG = unsigned long long;
|
using ULONGLONG = unsigned long long;
|
||||||
using LONG_PTR = long;
|
using LONG_PTR = int;
|
||||||
static_assert(sizeof(LONG_PTR) == sizeof(void *), "LONG_PTR must be pointer-sized");
|
using ULONG_PTR = unsigned int;
|
||||||
using ULONG_PTR = unsigned long;
|
using UINT_PTR = unsigned int;
|
||||||
static_assert(sizeof(ULONG_PTR) == sizeof(void *), "ULONG_PTR must be pointer-sized");
|
|
||||||
using UINT_PTR = unsigned long;
|
|
||||||
static_assert(sizeof(UINT_PTR) == sizeof(void *), "UINT_PTR must be pointer-sized");
|
|
||||||
using DWORD_PTR = ULONG_PTR;
|
using DWORD_PTR = ULONG_PTR;
|
||||||
using PDWORD_PTR = DWORD_PTR *;
|
using PDWORD_PTR = DWORD_PTR *;
|
||||||
using SHORT = short;
|
using SHORT = short;
|
||||||
@@ -97,7 +111,7 @@ using BYTE = unsigned char;
|
|||||||
using BOOLEAN = unsigned char;
|
using BOOLEAN = unsigned char;
|
||||||
using UINT = unsigned int;
|
using UINT = unsigned int;
|
||||||
using PUINT = UINT *;
|
using PUINT = UINT *;
|
||||||
using HKEY = VOID *;
|
using HKEY = HANDLE;
|
||||||
using PHKEY = HKEY *;
|
using PHKEY = HKEY *;
|
||||||
using PSID = VOID *;
|
using PSID = VOID *;
|
||||||
using REGSAM = DWORD;
|
using REGSAM = DWORD;
|
||||||
@@ -110,6 +124,8 @@ using PBYTE = BYTE *;
|
|||||||
using LPBYTE = BYTE *;
|
using LPBYTE = BYTE *;
|
||||||
using PWSTR = WCHAR *;
|
using PWSTR = WCHAR *;
|
||||||
|
|
||||||
|
constexpr HANDLE NO_HANDLE = 0;
|
||||||
|
|
||||||
using NTSTATUS = LONG;
|
using NTSTATUS = LONG;
|
||||||
using HRESULT = LONG;
|
using HRESULT = LONG;
|
||||||
|
|
||||||
@@ -271,20 +287,23 @@ constexpr SIZE_T kTlsSlotCount = 64;
|
|||||||
typedef struct _UNICODE_STRING {
|
typedef struct _UNICODE_STRING {
|
||||||
USHORT Length;
|
USHORT Length;
|
||||||
USHORT MaximumLength;
|
USHORT MaximumLength;
|
||||||
PWSTR Buffer;
|
GUEST_PTR Buffer;
|
||||||
} UNICODE_STRING, *PUNICODE_STRING;
|
} UNICODE_STRING;
|
||||||
|
typedef GUEST_PTR PUNICODE_STRING;
|
||||||
|
|
||||||
typedef struct _RTL_USER_PROCESS_PARAMETERS {
|
typedef struct _RTL_USER_PROCESS_PARAMETERS {
|
||||||
BYTE Reserved1[16];
|
BYTE Reserved1[16];
|
||||||
PVOID Reserved2[10];
|
GUEST_PTR Reserved2[10];
|
||||||
UNICODE_STRING ImagePathName;
|
UNICODE_STRING ImagePathName;
|
||||||
UNICODE_STRING CommandLine;
|
UNICODE_STRING CommandLine;
|
||||||
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
|
} RTL_USER_PROCESS_PARAMETERS, *PRTL_USER_PROCESS_PARAMETERS;
|
||||||
|
|
||||||
typedef struct _LIST_ENTRY {
|
typedef struct _LIST_ENTRY {
|
||||||
struct _LIST_ENTRY *Flink;
|
GUEST_PTR Flink;
|
||||||
struct _LIST_ENTRY *Blink;
|
GUEST_PTR Blink;
|
||||||
} LIST_ENTRY, *PLIST_ENTRY, PRLIST_ENTRY;
|
} LIST_ENTRY;
|
||||||
|
typedef GUEST_PTR PLIST_ENTRY;
|
||||||
|
typedef GUEST_PTR PRLIST_ENTRY;
|
||||||
|
|
||||||
typedef struct _PEB_LDR_DATA {
|
typedef struct _PEB_LDR_DATA {
|
||||||
BYTE Reserved1[8];
|
BYTE Reserved1[8];
|
||||||
@@ -299,23 +318,24 @@ typedef struct _PEB {
|
|||||||
BYTE Reserved1[2];
|
BYTE Reserved1[2];
|
||||||
BYTE BeingDebugged;
|
BYTE BeingDebugged;
|
||||||
BYTE Reserved2[1];
|
BYTE Reserved2[1];
|
||||||
PVOID Reserved3[2];
|
GUEST_PTR Reserved3[2];
|
||||||
PPEB_LDR_DATA Ldr;
|
GUEST_PTR Ldr;
|
||||||
PRTL_USER_PROCESS_PARAMETERS ProcessParameters;
|
GUEST_PTR ProcessParameters;
|
||||||
PVOID Reserved4[3];
|
GUEST_PTR Reserved4[3];
|
||||||
PVOID AtlThunkSListPtr;
|
GUEST_PTR AtlThunkSListPtr;
|
||||||
PVOID Reserved5;
|
GUEST_PTR Reserved5;
|
||||||
ULONG Reserved6;
|
ULONG Reserved6;
|
||||||
PVOID Reserved7;
|
GUEST_PTR Reserved7;
|
||||||
ULONG Reserved8;
|
ULONG Reserved8;
|
||||||
ULONG AtlThunkSListPtr32;
|
ULONG AtlThunkSListPtr32;
|
||||||
PVOID Reserved9[45];
|
GUEST_PTR Reserved9[45];
|
||||||
BYTE Reserved10[96];
|
BYTE Reserved10[96];
|
||||||
PPS_POST_PROCESS_INIT_ROUTINE PostProcessInitRoutine;
|
GUEST_PTR PostProcessInitRoutine;
|
||||||
BYTE Reserved11[128];
|
BYTE Reserved11[128];
|
||||||
PVOID Reserved12[1];
|
GUEST_PTR Reserved12[1];
|
||||||
ULONG SessionId;
|
ULONG SessionId;
|
||||||
} PEB, *PPEB;
|
} PEB;
|
||||||
|
typedef GUEST_PTR PPEB;
|
||||||
|
|
||||||
struct CLIENT_ID {
|
struct CLIENT_ID {
|
||||||
HANDLE UniqueProcess;
|
HANDLE UniqueProcess;
|
||||||
@@ -325,7 +345,7 @@ struct CLIENT_ID {
|
|||||||
struct _ACTIVATION_CONTEXT;
|
struct _ACTIVATION_CONTEXT;
|
||||||
|
|
||||||
typedef struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME {
|
typedef struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME {
|
||||||
struct _RTL_ACTIVATION_CONTEXT_STACK_FRAME *Previous;
|
GUEST_PTR Previous;
|
||||||
_ACTIVATION_CONTEXT *ActivationContext;
|
_ACTIVATION_CONTEXT *ActivationContext;
|
||||||
ULONG Flags;
|
ULONG Flags;
|
||||||
} RTL_ACTIVATION_CONTEXT_STACK_FRAME, *PRTL_ACTIVATION_CONTEXT_STACK_FRAME;
|
} RTL_ACTIVATION_CONTEXT_STACK_FRAME, *PRTL_ACTIVATION_CONTEXT_STACK_FRAME;
|
||||||
@@ -339,6 +359,7 @@ typedef struct _ACTIVATION_CONTEXT_STACK {
|
|||||||
} ACTIVATION_CONTEXT_STACK, *PACTIVATION_CONTEXT_STACK;
|
} ACTIVATION_CONTEXT_STACK, *PACTIVATION_CONTEXT_STACK;
|
||||||
|
|
||||||
#define GDI_BATCH_BUFFER_SIZE 0x136
|
#define GDI_BATCH_BUFFER_SIZE 0x136
|
||||||
|
|
||||||
typedef struct _GDI_TEB_BATCH {
|
typedef struct _GDI_TEB_BATCH {
|
||||||
ULONG Offset;
|
ULONG Offset;
|
||||||
HANDLE HDC;
|
HANDLE HDC;
|
||||||
@@ -346,83 +367,86 @@ typedef struct _GDI_TEB_BATCH {
|
|||||||
} GDI_TEB_BATCH, *PGDI_TEB_BATCH;
|
} GDI_TEB_BATCH, *PGDI_TEB_BATCH;
|
||||||
|
|
||||||
typedef struct _NT_TIB {
|
typedef struct _NT_TIB {
|
||||||
struct _EXCEPTION_REGISTRATION_RECORD *ExceptionList;
|
GUEST_PTR ExceptionList;
|
||||||
PVOID StackBase;
|
GUEST_PTR StackBase;
|
||||||
PVOID StackLimit;
|
GUEST_PTR StackLimit;
|
||||||
PVOID SubSystemTib;
|
GUEST_PTR SubSystemTib;
|
||||||
union {
|
union {
|
||||||
PVOID FiberData;
|
GUEST_PTR FiberData;
|
||||||
DWORD Version;
|
DWORD Version;
|
||||||
} DUMMYUNIONNAME;
|
} DUMMYUNIONNAME;
|
||||||
PVOID ArbitraryUserPointer;
|
GUEST_PTR ArbitraryUserPointer;
|
||||||
struct _NT_TIB *Self;
|
GUEST_PTR Self;
|
||||||
} NT_TIB, *PNT_TIB;
|
} NT_TIB, *PNT_TIB;
|
||||||
|
|
||||||
typedef struct _TEB {
|
typedef struct _TEB {
|
||||||
NT_TIB Tib;
|
NT_TIB Tib;
|
||||||
PVOID EnvironmentPointer;
|
GUEST_PTR EnvironmentPointer;
|
||||||
CLIENT_ID ClientId;
|
CLIENT_ID ClientId;
|
||||||
PVOID ActiveRpcHandle;
|
GUEST_PTR ActiveRpcHandle;
|
||||||
PVOID ThreadLocalStoragePointer;
|
GUEST_PTR ThreadLocalStoragePointer;
|
||||||
PPEB Peb;
|
PPEB Peb;
|
||||||
ULONG LastErrorValue;
|
ULONG LastErrorValue;
|
||||||
ULONG CountOfOwnedCriticalSections;
|
ULONG CountOfOwnedCriticalSections;
|
||||||
PVOID CsrClientThread;
|
GUEST_PTR CsrClientThread;
|
||||||
PVOID Win32ThreadInfo;
|
GUEST_PTR Win32ThreadInfo;
|
||||||
ULONG Win32ClientInfo[31]; /* used for user32 private data in Wine */
|
ULONG Win32ClientInfo[31]; /* used for user32 private data in Wine */
|
||||||
PVOID WOW32Reserved;
|
GUEST_PTR WOW32Reserved;
|
||||||
ULONG CurrentLocale;
|
ULONG CurrentLocale;
|
||||||
ULONG FpSoftwareStatusRegister;
|
ULONG FpSoftwareStatusRegister;
|
||||||
PVOID SystemReserved1[54]; /* used for kernel32 private data in Wine */
|
GUEST_PTR SystemReserved1[54]; /* used for kernel32 private data in Wine */
|
||||||
PVOID Spare1;
|
GUEST_PTR Spare1;
|
||||||
LONG ExceptionCode;
|
LONG ExceptionCode;
|
||||||
PVOID ActivationContextStackPointer;
|
GUEST_PTR ActivationContextStackPointer;
|
||||||
BYTE SpareBytes1[36];
|
BYTE SpareBytes1[36];
|
||||||
PVOID SystemReserved2[10]; /* used for ntdll private data in Wine */
|
GUEST_PTR SystemReserved2[10]; /* used for ntdll private data in Wine */
|
||||||
GDI_TEB_BATCH GdiTebBatch;
|
GDI_TEB_BATCH GdiTebBatch;
|
||||||
ULONG gdiRgn;
|
ULONG gdiRgn;
|
||||||
ULONG gdiPen;
|
ULONG gdiPen;
|
||||||
ULONG gdiBrush;
|
ULONG gdiBrush;
|
||||||
CLIENT_ID RealClientId;
|
CLIENT_ID RealClientId;
|
||||||
HANDLE GdiCachedProcessHandle;
|
GUEST_PTR GdiCachedProcessHandle;
|
||||||
ULONG GdiClientPID;
|
ULONG GdiClientPID;
|
||||||
ULONG GdiClientTID;
|
ULONG GdiClientTID;
|
||||||
PVOID GdiThreadLocaleInfo;
|
GUEST_PTR GdiThreadLocaleInfo;
|
||||||
PVOID UserReserved[5];
|
GUEST_PTR UserReserved[5];
|
||||||
PVOID glDispatchTable[280];
|
GUEST_PTR glDispatchTable[280];
|
||||||
ULONG glReserved1[26];
|
ULONG glReserved1[26];
|
||||||
PVOID glReserved2;
|
GUEST_PTR glReserved2;
|
||||||
PVOID glSectionInfo;
|
GUEST_PTR glSectionInfo;
|
||||||
PVOID glSection;
|
GUEST_PTR glSection;
|
||||||
PVOID glTable;
|
GUEST_PTR glTable;
|
||||||
PVOID glCurrentRC;
|
GUEST_PTR glCurrentRC;
|
||||||
PVOID glContext;
|
GUEST_PTR glContext;
|
||||||
ULONG LastStatusValue;
|
ULONG LastStatusValue;
|
||||||
UNICODE_STRING StaticUnicodeString;
|
UNICODE_STRING StaticUnicodeString;
|
||||||
WCHAR StaticUnicodeBuffer[261];
|
WCHAR StaticUnicodeBuffer[261];
|
||||||
PVOID DeallocationStack;
|
GUEST_PTR DeallocationStack;
|
||||||
PVOID TlsSlots[64];
|
GUEST_PTR TlsSlots[64];
|
||||||
LIST_ENTRY TlsLinks;
|
LIST_ENTRY TlsLinks;
|
||||||
PVOID Vdm;
|
GUEST_PTR Vdm;
|
||||||
PVOID ReservedForNtRpc;
|
GUEST_PTR ReservedForNtRpc;
|
||||||
PVOID DbgSsReserved[2];
|
GUEST_PTR DbgSsReserved[2];
|
||||||
ULONG HardErrorDisabled;
|
ULONG HardErrorDisabled;
|
||||||
PVOID Instrumentation[16];
|
GUEST_PTR Instrumentation[16];
|
||||||
PVOID WinSockData;
|
GUEST_PTR WinSockData;
|
||||||
ULONG GdiBatchCount;
|
ULONG GdiBatchCount;
|
||||||
ULONG Spare2;
|
ULONG Spare2;
|
||||||
ULONG Spare3;
|
ULONG Spare3;
|
||||||
ULONG Spare4;
|
ULONG Spare4;
|
||||||
PVOID ReservedForOle;
|
GUEST_PTR ReservedForOle;
|
||||||
ULONG WaitingOnLoaderLock;
|
ULONG WaitingOnLoaderLock;
|
||||||
PVOID Reserved5[3];
|
GUEST_PTR Reserved5[3];
|
||||||
PVOID *TlsExpansionSlots;
|
GUEST_PTR TlsExpansionSlots;
|
||||||
// wibo
|
// wibo
|
||||||
WORD CurrentFsSelector;
|
WORD CurrentFsSelector;
|
||||||
WORD CurrentGsSelector;
|
WORD CurrentGsSelector;
|
||||||
PVOID CurrentStackPointer;
|
void *CurrentStackPointer;
|
||||||
} TEB, *PTEB;
|
#ifdef __x86_64__
|
||||||
|
void *CurrentFsBase;
|
||||||
|
#endif
|
||||||
|
} TEB;
|
||||||
|
typedef GUEST_PTR PTEB;
|
||||||
#ifndef offsetof
|
#ifndef offsetof
|
||||||
#define offsetof(type, member) __builtin_offsetof(type, member)
|
#define offsetof(type, member) __builtin_offsetof(type, member)
|
||||||
#endif
|
#endif
|
||||||
@@ -436,8 +460,8 @@ static_assert(offsetof(TEB, DeallocationStack) == 0xE0C, "DeallocationStack offs
|
|||||||
static_assert(offsetof(TEB, TlsSlots) == 0xE10, "TLS slots offset mismatch");
|
static_assert(offsetof(TEB, TlsSlots) == 0xE10, "TLS slots offset mismatch");
|
||||||
|
|
||||||
typedef struct _MEMORY_BASIC_INFORMATION {
|
typedef struct _MEMORY_BASIC_INFORMATION {
|
||||||
PVOID BaseAddress;
|
GUEST_PTR BaseAddress;
|
||||||
PVOID AllocationBase;
|
GUEST_PTR AllocationBase;
|
||||||
DWORD AllocationProtect;
|
DWORD AllocationProtect;
|
||||||
SIZE_T RegionSize;
|
SIZE_T RegionSize;
|
||||||
DWORD State;
|
DWORD State;
|
||||||
@@ -451,12 +475,12 @@ typedef struct _iobuf {
|
|||||||
_iobuf() : _file(-1) {}
|
_iobuf() : _file(-1) {}
|
||||||
explicit _iobuf(int file) : _file(file) {}
|
explicit _iobuf(int file) : _file(file) {}
|
||||||
|
|
||||||
char *_ptr = nullptr;
|
GUEST_PTR _ptr = GUEST_NULL;
|
||||||
int _cnt = 0;
|
int _cnt = 0;
|
||||||
char *_base = nullptr;
|
GUEST_PTR _base = GUEST_NULL;
|
||||||
int _flag = 0;
|
int _flag = 0;
|
||||||
int _file;
|
int _file;
|
||||||
int _charbuf = 0;
|
int _charbuf = 0;
|
||||||
int _bufsiz = 0;
|
int _bufsiz = 0;
|
||||||
char *_tmpfname = nullptr;
|
GUEST_PTR _tmpfname = GUEST_NULL;
|
||||||
} _FILE;
|
} _FILE;
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import tempfile
|
import tempfile
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from enum import IntEnum
|
from enum import Enum, IntEnum
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Iterable, List, Optional
|
from typing import Iterable, List, Optional
|
||||||
|
|
||||||
@@ -50,6 +50,11 @@ if "LIBCLANG_PATH" in os.environ:
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class Arch(str, Enum):
|
||||||
|
X86 = "x86"
|
||||||
|
X86_64 = "x86_64"
|
||||||
|
|
||||||
|
|
||||||
class CallingConv(IntEnum):
|
class CallingConv(IntEnum):
|
||||||
"""CXCallingConv enum values from clang-c/Index.h"""
|
"""CXCallingConv enum values from clang-c/Index.h"""
|
||||||
|
|
||||||
@@ -91,13 +96,30 @@ def _get_function_calling_conv(func_type: CXType) -> CallingConv:
|
|||||||
return CallingConv(_get_calling_conv(func_type))
|
return CallingConv(_get_calling_conv(func_type))
|
||||||
|
|
||||||
|
|
||||||
|
class ArgClass(str, Enum):
|
||||||
|
INT = "int"
|
||||||
|
MEMORY = "memory"
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ArgInfo:
|
class ArgInfo:
|
||||||
|
type: Type
|
||||||
|
arg_class: ArgClass
|
||||||
|
sign_extended: bool
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ArgPlacement:
|
||||||
size: int
|
size: int
|
||||||
slot_size: int
|
slot_size: int
|
||||||
primitive: bool
|
stack_offset: Optional[int] = None
|
||||||
sign_extended: bool
|
register: Optional[str] = None
|
||||||
type: Type
|
|
||||||
|
def __init__(self, arg: ArgInfo, arch: Arch):
|
||||||
|
self.size = arg.type.get_canonical().get_size()
|
||||||
|
self.slot_size = _slot_size_for_arch(arg, arch)
|
||||||
|
self.register = None
|
||||||
|
self.stack_offset = None
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -108,7 +130,7 @@ class FuncInfo:
|
|||||||
source_cc: CallingConv
|
source_cc: CallingConv
|
||||||
target_cc: CallingConv
|
target_cc: CallingConv
|
||||||
variadic: bool
|
variadic: bool
|
||||||
return_type: Type
|
return_type: ArgInfo
|
||||||
args: List[ArgInfo] = field(default_factory=list)
|
args: List[ArgInfo] = field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
@@ -118,7 +140,7 @@ class TypedefInfo:
|
|||||||
source_cc: CallingConv
|
source_cc: CallingConv
|
||||||
target_cc: CallingConv
|
target_cc: CallingConv
|
||||||
variadic: bool
|
variadic: bool
|
||||||
return_type: Type
|
return_type: ArgInfo
|
||||||
args: List[ArgInfo] = field(default_factory=list)
|
args: List[ArgInfo] = field(default_factory=list)
|
||||||
|
|
||||||
|
|
||||||
@@ -210,43 +232,146 @@ SIGNED_KINDS = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _calculate_arg_info(t: Type) -> ArgInfo:
|
||||||
|
canonical = t.get_canonical()
|
||||||
|
|
||||||
|
# if canonical.kind == TypeKind.RECORD:
|
||||||
|
# arg_class = ArgClass.MEMORY
|
||||||
|
# else:
|
||||||
|
arg_class = ArgClass.INT
|
||||||
|
|
||||||
|
if canonical.kind == TypeKind.POINTER:
|
||||||
|
pointee = canonical.get_pointee()
|
||||||
|
if pointee.kind == TypeKind.POINTER:
|
||||||
|
print(f"Bugprone: Pointer to pointer ({_type_to_string(t)})")
|
||||||
|
|
||||||
|
# Sign-extend signed integers and HANDLE-like typedefs
|
||||||
|
is_sign_extended = canonical.kind in SIGNED_KINDS or _is_handle_typedef(t)
|
||||||
|
|
||||||
|
return ArgInfo(
|
||||||
|
arg_class=arg_class,
|
||||||
|
sign_extended=is_sign_extended,
|
||||||
|
type=t,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _collect_args(func_type: CXType) -> List[ArgInfo]:
|
def _collect_args(func_type: CXType) -> List[ArgInfo]:
|
||||||
"""Collect argument information for a function."""
|
"""Collect argument information for a function."""
|
||||||
args: List[ArgInfo] = []
|
args: List[ArgInfo] = []
|
||||||
for t in func_type.argument_types():
|
for t in func_type.argument_types():
|
||||||
size = t.get_size()
|
args.append(_calculate_arg_info(t))
|
||||||
canonical = t.get_canonical()
|
|
||||||
|
|
||||||
# Determine if primitive (not struct/union)
|
|
||||||
is_primitive = canonical.kind != TypeKind.RECORD
|
|
||||||
|
|
||||||
# Determine if sign-extended
|
|
||||||
# Sign-extend signed integers and HANDLE-like typedefs
|
|
||||||
is_sign_extended = canonical in SIGNED_KINDS or _is_handle_typedef(t)
|
|
||||||
|
|
||||||
# Calculate stack slot size
|
|
||||||
if size <= 4:
|
|
||||||
slot_size = 4
|
|
||||||
elif size <= 8:
|
|
||||||
slot_size = 8
|
|
||||||
else:
|
|
||||||
raise NotImplementedError(
|
|
||||||
f"Argument size {size} not supported for function {func_type.spelling}"
|
|
||||||
)
|
|
||||||
|
|
||||||
args.append(
|
|
||||||
ArgInfo(
|
|
||||||
size=size,
|
|
||||||
slot_size=slot_size,
|
|
||||||
primitive=is_primitive,
|
|
||||||
sign_extended=is_sign_extended,
|
|
||||||
type=t,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
|
||||||
def collect_functions(tu: TranslationUnit, ns_filter: Optional[str]) -> List[FuncInfo]:
|
def _slot_size_for_arch(arg: ArgInfo, arch: Arch) -> int:
|
||||||
|
"""Return the slot size (in bytes) used to pass an argument on the given architecture."""
|
||||||
|
canonical = arg.type.get_canonical()
|
||||||
|
if canonical.kind == TypeKind.POINTER:
|
||||||
|
return 8 if arch == Arch.X86_64 else 4
|
||||||
|
size = canonical.get_size()
|
||||||
|
if arch == Arch.X86:
|
||||||
|
if size <= 4:
|
||||||
|
return 4
|
||||||
|
if size <= 8:
|
||||||
|
return 8
|
||||||
|
elif arch == Arch.X86_64:
|
||||||
|
if size <= 8:
|
||||||
|
return 8
|
||||||
|
raise NotImplementedError(
|
||||||
|
f"Argument size {size} not supported for architecture {arch.value}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass
|
||||||
|
class ArgLayout:
|
||||||
|
args: List[ArgPlacement]
|
||||||
|
stack_size: int
|
||||||
|
|
||||||
|
|
||||||
|
def compute_arg_layout(
|
||||||
|
args: List[ArgInfo],
|
||||||
|
cc: CallingConv,
|
||||||
|
arch: Arch,
|
||||||
|
stack_offset: int = 0,
|
||||||
|
skip_args: int = 0,
|
||||||
|
) -> ArgLayout:
|
||||||
|
"""Compute how each argument is passed for the given calling convention and arch."""
|
||||||
|
|
||||||
|
placements: List[ArgPlacement] = []
|
||||||
|
stack_size = 0
|
||||||
|
gpr_order: List[str] = []
|
||||||
|
gpr_index = skip_args
|
||||||
|
|
||||||
|
if arch == Arch.X86 and cc == CallingConv.X86_FASTCALL:
|
||||||
|
gpr_order = ["ecx", "edx"]
|
||||||
|
elif arch == Arch.X86_64 and cc == CallingConv.C:
|
||||||
|
gpr_order = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"]
|
||||||
|
|
||||||
|
# Offset our stack based on number of extra arguments
|
||||||
|
# We assume that every arg represented by skip_args fits in a register
|
||||||
|
register_size = 8 if arch == Arch.X86_64 else 4
|
||||||
|
consumed_stack = max(0, skip_args - len(gpr_order)) * register_size
|
||||||
|
stack_offset += consumed_stack
|
||||||
|
stack_size += consumed_stack
|
||||||
|
|
||||||
|
def _push_stack(arg: ArgInfo) -> None:
|
||||||
|
nonlocal stack_offset
|
||||||
|
nonlocal stack_size
|
||||||
|
placement = ArgPlacement(arg, arch)
|
||||||
|
placement.stack_offset = stack_offset
|
||||||
|
placements.append(placement)
|
||||||
|
stack_offset += placement.slot_size
|
||||||
|
stack_size += placement.slot_size
|
||||||
|
|
||||||
|
def _push_register(arg: ArgInfo) -> None:
|
||||||
|
nonlocal gpr_index
|
||||||
|
placement = ArgPlacement(arg, arch)
|
||||||
|
placement.register = gpr_order[gpr_index]
|
||||||
|
placements.append(placement)
|
||||||
|
gpr_index += 1
|
||||||
|
|
||||||
|
# Special case for x86 fastcall: stop using registers if any spill onto the stack
|
||||||
|
if arch == Arch.X86 and cc == CallingConv.X86_FASTCALL:
|
||||||
|
stack_args_start = 0
|
||||||
|
for i in range(min(len(gpr_order), len(args))):
|
||||||
|
if gpr_index >= len(gpr_order):
|
||||||
|
break
|
||||||
|
arg = args[i]
|
||||||
|
slot_size = _slot_size_for_arch(arg, arch)
|
||||||
|
if arg.arg_class == ArgClass.INT and slot_size == 4:
|
||||||
|
_push_register(arg)
|
||||||
|
stack_args_start += 1
|
||||||
|
else:
|
||||||
|
break
|
||||||
|
|
||||||
|
for i in range(stack_args_start, len(args)):
|
||||||
|
_push_stack(args[i])
|
||||||
|
else:
|
||||||
|
for arg in args:
|
||||||
|
slot_size = _slot_size_for_arch(arg, arch)
|
||||||
|
if (
|
||||||
|
arg.arg_class == ArgClass.INT
|
||||||
|
and slot_size <= register_size
|
||||||
|
and gpr_index < len(gpr_order)
|
||||||
|
):
|
||||||
|
_push_register(arg)
|
||||||
|
else:
|
||||||
|
_push_stack(arg)
|
||||||
|
|
||||||
|
return ArgLayout(args=placements, stack_size=stack_size)
|
||||||
|
|
||||||
|
|
||||||
|
def describe_arg_placement(placement: ArgPlacement) -> str:
|
||||||
|
if placement.register is not None:
|
||||||
|
return f"{placement.register}[{placement.slot_size}]"
|
||||||
|
if placement.stack_offset is not None:
|
||||||
|
return f"stack+{placement.stack_offset}[{placement.slot_size}]"
|
||||||
|
raise ValueError(f"Unassigned placement {placement}")
|
||||||
|
|
||||||
|
|
||||||
|
def collect_functions(
|
||||||
|
tu: TranslationUnit, ns_filter: Optional[str], arch: Arch
|
||||||
|
) -> List[FuncInfo]:
|
||||||
want_ns = ns_filter.split("::") if ns_filter else None
|
want_ns = ns_filter.split("::") if ns_filter else None
|
||||||
out: dict[str, FuncInfo] = {}
|
out: dict[str, FuncInfo] = {}
|
||||||
|
|
||||||
@@ -268,7 +393,7 @@ def collect_functions(tu: TranslationUnit, ns_filter: Optional[str]) -> List[Fun
|
|||||||
source_cc=source_cc,
|
source_cc=source_cc,
|
||||||
target_cc=_get_function_calling_conv(node.type),
|
target_cc=_get_function_calling_conv(node.type),
|
||||||
variadic=node.type.is_function_variadic(),
|
variadic=node.type.is_function_variadic(),
|
||||||
return_type=node.type.get_result(),
|
return_type=_calculate_arg_info(node.type.get_result()),
|
||||||
args=_collect_args(node.type),
|
args=_collect_args(node.type),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -292,7 +417,7 @@ def _type_to_string(t: CXType) -> str:
|
|||||||
return spelling
|
return spelling
|
||||||
|
|
||||||
|
|
||||||
def collect_typedefs(tu: TranslationUnit) -> List[TypedefInfo]:
|
def collect_typedefs(tu: TranslationUnit, arch: Arch) -> List[TypedefInfo]:
|
||||||
"""Collect function pointer typedefs and type aliases from the translation unit."""
|
"""Collect function pointer typedefs and type aliases from the translation unit."""
|
||||||
out: dict[str, TypedefInfo] = {}
|
out: dict[str, TypedefInfo] = {}
|
||||||
|
|
||||||
@@ -309,17 +434,13 @@ def collect_typedefs(tu: TranslationUnit) -> List[TypedefInfo]:
|
|||||||
if target_cc == CallingConv.DEFAULT:
|
if target_cc == CallingConv.DEFAULT:
|
||||||
return # No CC annotation; skip
|
return # No CC annotation; skip
|
||||||
|
|
||||||
variadic = func_type.is_function_variadic()
|
|
||||||
args = _collect_args(func_type)
|
|
||||||
return_type = func_type.get_result()
|
|
||||||
|
|
||||||
out[name] = TypedefInfo(
|
out[name] = TypedefInfo(
|
||||||
name=name,
|
name=name,
|
||||||
source_cc=source_cc,
|
source_cc=source_cc,
|
||||||
target_cc=target_cc,
|
target_cc=target_cc,
|
||||||
variadic=variadic,
|
variadic=func_type.is_function_variadic(),
|
||||||
return_type=return_type,
|
return_type=_calculate_arg_info(func_type.get_result()),
|
||||||
args=args,
|
args=_collect_args(func_type),
|
||||||
)
|
)
|
||||||
|
|
||||||
def visit(node: Cursor) -> None:
|
def visit(node: Cursor) -> None:
|
||||||
@@ -372,17 +493,15 @@ def collect_variables(tu: TranslationUnit, ns_filter: Optional[str]) -> List[Var
|
|||||||
return sorted(out.values(), key=lambda v: v.name)
|
return sorted(out.values(), key=lambda v: v.name)
|
||||||
|
|
||||||
|
|
||||||
def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]):
|
def emit_cc_thunk32(f: FuncInfo | TypedefInfo, lines: List[str]):
|
||||||
if isinstance(f, TypedefInfo):
|
if isinstance(f, TypedefInfo):
|
||||||
# Host-to-guest
|
# Host-to-guest
|
||||||
target = "[eax+4]"
|
call_target = "[eax+4]"
|
||||||
arg_off = 8
|
|
||||||
align = 0
|
align = 0
|
||||||
host_to_guest = True
|
host_to_guest = True
|
||||||
elif isinstance(f, FuncInfo):
|
elif isinstance(f, FuncInfo):
|
||||||
# Guest-to-host
|
# Guest-to-host
|
||||||
target = f.mangled
|
call_target = f.mangled
|
||||||
arg_off = 4
|
|
||||||
align = 16
|
align = 16
|
||||||
host_to_guest = False
|
host_to_guest = False
|
||||||
|
|
||||||
@@ -391,49 +510,32 @@ def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]):
|
|||||||
assert f.source_cc == CallingConv.C and f.target_cc == CallingConv.C, (
|
assert f.source_cc == CallingConv.C and f.target_cc == CallingConv.C, (
|
||||||
"Variadic functions must be cdecl"
|
"Variadic functions must be cdecl"
|
||||||
)
|
)
|
||||||
lines.append(f"\tjmp {target}")
|
lines.append(f"\tjmp {call_target}")
|
||||||
return
|
return
|
||||||
|
|
||||||
# Compute argument stack offsets
|
source_layout = compute_arg_layout(
|
||||||
offsets: List[int] = []
|
f.args,
|
||||||
for arg in f.args:
|
f.source_cc,
|
||||||
offsets.append(arg_off)
|
Arch.X86,
|
||||||
arg_off += arg.slot_size
|
stack_offset=4,
|
||||||
|
skip_args=1 if host_to_guest else 0,
|
||||||
reg_indices: List[int] = []
|
|
||||||
if f.target_cc == CallingConv.X86_FASTCALL:
|
|
||||||
# Store the first two non-record 4-byte args in ECX/EDX for GCC/Clang x86 fastcall
|
|
||||||
if len(f.args) >= 1 and f.args[0].primitive and f.args[0].slot_size == 4:
|
|
||||||
reg_indices.append(0) # ECX
|
|
||||||
if len(f.args) >= 2 and f.args[1].primitive and f.args[1].slot_size == 4:
|
|
||||||
reg_indices.append(1) # EDX
|
|
||||||
elif f.target_cc == CallingConv.C or f.target_cc == CallingConv.X86_STDCALL:
|
|
||||||
# No register args for cdecl or stdcall
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
raise NotImplementedError(
|
|
||||||
f"Unsupported target calling convention {f.target_cc.name} for function {f.name}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Bytes we will push for the call (exclude args passed in registers)
|
|
||||||
stack_bytes = sum(
|
|
||||||
arg.slot_size for i, arg in enumerate(f.args) if i not in reg_indices
|
|
||||||
)
|
)
|
||||||
|
target_layout = compute_arg_layout(f.args, f.target_cc, Arch.X86)
|
||||||
|
|
||||||
# Get current TIB
|
# Get current TEB
|
||||||
if host_to_guest:
|
if host_to_guest:
|
||||||
lines.append("\tmov ecx, gs:[currentThreadTeb@ntpoff]")
|
lines.append("\tmov ecx, gs:[currentThreadTeb@ntpoff]")
|
||||||
else:
|
else:
|
||||||
lines.append("\tmov ecx, fs:[0x18]")
|
lines.append("\tmov ecx, fs:[TEB_SELF]")
|
||||||
|
|
||||||
# Swap fs and gs
|
# Swap fs and gs
|
||||||
lines.append("\tmov ax, fs")
|
lines.append("\tmov ax, fs")
|
||||||
lines.append("\tmov dx, word ptr [ecx+0xf98]")
|
lines.append("\tmov dx, word ptr [ecx+TEB_FS_SEL]")
|
||||||
lines.append("\tmov word ptr [ecx+0xf98], ax")
|
lines.append("\tmov word ptr [ecx+TEB_FS_SEL], ax")
|
||||||
lines.append("\tmov fs, dx")
|
lines.append("\tmov fs, dx")
|
||||||
lines.append("\tmov ax, gs")
|
lines.append("\tmov ax, gs")
|
||||||
lines.append("\tmov dx, word ptr [ecx+0xf9a]")
|
lines.append("\tmov dx, word ptr [ecx+TEB_GS_SEL]")
|
||||||
lines.append("\tmov word ptr [ecx+0xf9a], ax")
|
lines.append("\tmov word ptr [ecx+TEB_GS_SEL], ax")
|
||||||
lines.append("\tmov gs, dx")
|
lines.append("\tmov gs, dx")
|
||||||
|
|
||||||
# Store guest stack pointer in eax for arg access
|
# Store guest stack pointer in eax for arg access
|
||||||
@@ -442,48 +544,60 @@ def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]):
|
|||||||
|
|
||||||
# Swap stack pointer
|
# Swap stack pointer
|
||||||
lines.append("\tpush ebp")
|
lines.append("\tpush ebp")
|
||||||
lines.append("\tmov ebp, dword ptr [ecx+0xf9c]")
|
lines.append("\tmov ebp, dword ptr [ecx+TEB_SP]")
|
||||||
lines.append("\tmov dword ptr [ecx+0xf9c], esp")
|
lines.append("\tmov dword ptr [ecx+TEB_SP], esp")
|
||||||
lines.append("\tmov esp, ebp")
|
lines.append("\tmov esp, ebp")
|
||||||
|
|
||||||
# Allocate stack space for arguments
|
# Allocate stack space for arguments
|
||||||
if stack_bytes > 0:
|
if target_layout.stack_size > 0:
|
||||||
lines.append(f"\tsub esp, {stack_bytes}")
|
lines.append(f"\tsub esp, {target_layout.stack_size}")
|
||||||
|
|
||||||
# Align stack if needed (must be done after allocating args)
|
# Align stack if needed (must be done after allocating args)
|
||||||
if align > 0:
|
if align > 0:
|
||||||
lines.append(f"\tand esp, ~{align - 1}")
|
lines.append(f"\tand esp, ~{align - 1}")
|
||||||
|
|
||||||
# Copy args onto stack
|
# Copy args onto stack for the callee
|
||||||
cur_off = 0
|
for idx, target in enumerate(target_layout.args):
|
||||||
for i, arg in enumerate(f.args):
|
if target.stack_offset is None:
|
||||||
if i in reg_indices:
|
|
||||||
continue
|
continue
|
||||||
base = offsets[i]
|
|
||||||
for part_off in range(0, arg.slot_size, 4):
|
source = source_layout.args[idx]
|
||||||
lines.append(f"\tmov ecx, [eax+{base + part_off}]")
|
if source.stack_offset is None:
|
||||||
lines.append(f"\tmov [esp+{cur_off + part_off}], ecx")
|
raise NotImplementedError(
|
||||||
cur_off += arg.slot_size
|
f"Source calling convention {f.source_cc.name} requires register argument {idx}; not implemented"
|
||||||
|
)
|
||||||
|
|
||||||
|
if source.slot_size != target.slot_size:
|
||||||
|
raise NotImplementedError(
|
||||||
|
f"Argument {idx} requires size conversion {source.slot_size}->{target.slot_size}; not implemented"
|
||||||
|
)
|
||||||
|
|
||||||
|
for off in range(0, target.slot_size, 4):
|
||||||
|
lines.append(f"\tmov ecx, [eax+{source.stack_offset + off}]")
|
||||||
|
lines.append(f"\tmov [esp+{target.stack_offset + off}], ecx")
|
||||||
|
|
||||||
# Load args into registers as needed
|
# Load args into registers as needed
|
||||||
if len(reg_indices) > 0:
|
for idx, target in enumerate(target_layout.args):
|
||||||
i = reg_indices[0]
|
if target.register is None:
|
||||||
offset = offsets[i]
|
continue
|
||||||
lines.append(f"\tmov ecx, [eax+{offset}]")
|
|
||||||
if len(reg_indices) > 1:
|
source = source_layout.args[idx]
|
||||||
i = reg_indices[1]
|
if source.stack_offset is None:
|
||||||
offset = offsets[i]
|
raise NotImplementedError(
|
||||||
lines.append(f"\tmov edx, [eax+{offset}]")
|
f"Source calling convention {f.source_cc.name} requires register argument {idx}; not implemented"
|
||||||
|
)
|
||||||
|
|
||||||
|
lines.append(f"\tmov {target.register}, [eax+{source.stack_offset}]")
|
||||||
|
|
||||||
# Call into target
|
# Call into target
|
||||||
lines.append(f"\tcall {target}")
|
lines.append(f"\tcall {call_target}")
|
||||||
|
|
||||||
# Determine if we can clobber eax/edx
|
# Determine if we can clobber eax/edx
|
||||||
if f.return_type.kind == TypeKind.RECORD:
|
if f.return_type.arg_class != ArgClass.INT:
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
f"Struct return type not supported for function {f.name}"
|
f"Unsupported return type class {f.return_type.arg_class.value} for function {f.name}"
|
||||||
)
|
)
|
||||||
return_size = f.return_type.get_size()
|
return_size = f.return_type.type.get_size()
|
||||||
save_eax = return_size > 0
|
save_eax = return_size > 0
|
||||||
save_edx = return_size > 4
|
save_edx = return_size > 4
|
||||||
if return_size > 8:
|
if return_size > 8:
|
||||||
@@ -497,16 +611,16 @@ def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]):
|
|||||||
if save_edx:
|
if save_edx:
|
||||||
lines.append("\tpush edx")
|
lines.append("\tpush edx")
|
||||||
if host_to_guest:
|
if host_to_guest:
|
||||||
lines.append("\tmov ecx, fs:[0x18]")
|
lines.append("\tmov ecx, fs:[TEB_SELF]")
|
||||||
else:
|
else:
|
||||||
lines.append("\tmov ecx, gs:[currentThreadTeb@ntpoff]")
|
lines.append("\tmov ecx, gs:[currentThreadTeb@ntpoff]")
|
||||||
lines.append("\tmov ax, fs")
|
lines.append("\tmov ax, fs")
|
||||||
lines.append("\tmov dx, word ptr [ecx+0xf98]")
|
lines.append("\tmov dx, word ptr [ecx+TEB_FS_SEL]")
|
||||||
lines.append("\tmov word ptr [ecx+0xf98], ax")
|
lines.append("\tmov word ptr [ecx+TEB_FS_SEL], ax")
|
||||||
lines.append("\tmov fs, dx")
|
lines.append("\tmov fs, dx")
|
||||||
lines.append("\tmov ax, gs")
|
lines.append("\tmov ax, gs")
|
||||||
lines.append("\tmov dx, word ptr [ecx+0xf9a]")
|
lines.append("\tmov dx, word ptr [ecx+TEB_GS_SEL]")
|
||||||
lines.append("\tmov word ptr [ecx+0xf9a], ax")
|
lines.append("\tmov word ptr [ecx+TEB_GS_SEL], ax")
|
||||||
lines.append("\tmov gs, dx")
|
lines.append("\tmov gs, dx")
|
||||||
if save_edx:
|
if save_edx:
|
||||||
lines.append("\tpop edx")
|
lines.append("\tpop edx")
|
||||||
@@ -515,29 +629,293 @@ def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str]):
|
|||||||
|
|
||||||
# Swap stack pointer
|
# Swap stack pointer
|
||||||
lines.append("\tmov esp, ebp") # Clean up arg space
|
lines.append("\tmov esp, ebp") # Clean up arg space
|
||||||
lines.append("\tmov ebp, dword ptr [ecx+0xf9c]")
|
lines.append("\tmov ebp, dword ptr [ecx+TEB_SP]")
|
||||||
lines.append("\tmov dword ptr [ecx+0xf9c], esp")
|
lines.append("\tmov dword ptr [ecx+TEB_SP], esp")
|
||||||
|
|
||||||
# Restore stack and frame pointer
|
# Restore stack and frame pointer
|
||||||
lines.append("\tleave")
|
lines.append("\tleave")
|
||||||
|
|
||||||
# Return to guest
|
# Return to guest
|
||||||
if f.source_cc == CallingConv.X86_STDCALL:
|
if f.source_cc == CallingConv.X86_STDCALL and source_layout.stack_size > 0:
|
||||||
ret_bytes = sum(arg.slot_size for arg in f.args)
|
lines.append(f"\tret {source_layout.stack_size}")
|
||||||
elif f.source_cc == CallingConv.C:
|
|
||||||
ret_bytes = 0
|
|
||||||
else:
|
|
||||||
raise NotImplementedError(
|
|
||||||
f"Unsupported source calling convention {f.source_cc.name} for function {f.name}"
|
|
||||||
)
|
|
||||||
if ret_bytes > 0:
|
|
||||||
lines.append(f"\tret {ret_bytes}")
|
|
||||||
else:
|
else:
|
||||||
lines.append("\tret")
|
lines.append("\tret")
|
||||||
|
|
||||||
|
|
||||||
|
def _x64_register_by_slot_size(reg: str, slot_size: int) -> str:
|
||||||
|
if slot_size == 8:
|
||||||
|
return reg
|
||||||
|
if reg in ["rax", "rbx", "rcx", "rdx", "rsi", "rdi", "rbp", "rsp"]:
|
||||||
|
if slot_size == 4:
|
||||||
|
return f"e{reg[1:]}"
|
||||||
|
elif slot_size == 2:
|
||||||
|
return reg[1:]
|
||||||
|
elif slot_size == 1:
|
||||||
|
if reg in ["rax", "rbx", "rcx", "rdx"]:
|
||||||
|
return f"{reg[1]}l"
|
||||||
|
elif reg in ["rsi", "rdi"]:
|
||||||
|
return f"{reg[1]}il"
|
||||||
|
else:
|
||||||
|
return f"{reg[1]}pl"
|
||||||
|
if slot_size == 4:
|
||||||
|
return f"{reg}d"
|
||||||
|
if slot_size == 2:
|
||||||
|
return f"{reg}w"
|
||||||
|
if slot_size == 1:
|
||||||
|
return f"{reg}b"
|
||||||
|
raise NotImplementedError(f"Unsupported register {reg} for slot size {slot_size}")
|
||||||
|
|
||||||
|
|
||||||
|
def _x64_ptr_type_by_slot_size(slot_size) -> str:
|
||||||
|
if slot_size == 4:
|
||||||
|
return "dword ptr"
|
||||||
|
elif slot_size == 8:
|
||||||
|
return "qword ptr"
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Unsupported slot size {slot_size}")
|
||||||
|
|
||||||
|
|
||||||
|
def emit_cc_thunk64(f: FuncInfo | TypedefInfo, lines: List[str]):
|
||||||
|
if isinstance(f, TypedefInfo):
|
||||||
|
# Host-to-guest
|
||||||
|
call_target = "edi"
|
||||||
|
align = 0
|
||||||
|
host_to_guest = True
|
||||||
|
elif isinstance(f, FuncInfo):
|
||||||
|
# Guest-to-host
|
||||||
|
call_target = f.mangled
|
||||||
|
align = 16
|
||||||
|
host_to_guest = False
|
||||||
|
|
||||||
|
if f.variadic:
|
||||||
|
# Variadic functions are not yet supported for calling convention conversion.
|
||||||
|
assert f.source_cc == CallingConv.C and f.target_cc == CallingConv.C, (
|
||||||
|
"Variadic functions must be cdecl"
|
||||||
|
)
|
||||||
|
lines.append(f"\tjmp {call_target}")
|
||||||
|
return
|
||||||
|
|
||||||
|
source_layout = compute_arg_layout(
|
||||||
|
f.args,
|
||||||
|
f.source_cc,
|
||||||
|
Arch.X86_64 if host_to_guest else Arch.X86,
|
||||||
|
stack_offset=24 if host_to_guest else 16,
|
||||||
|
skip_args=1 if host_to_guest else 0,
|
||||||
|
)
|
||||||
|
target_layout = compute_arg_layout(
|
||||||
|
f.args, f.target_cc, Arch.X86 if host_to_guest else Arch.X86_64
|
||||||
|
)
|
||||||
|
|
||||||
|
if host_to_guest:
|
||||||
|
lines.append(".code64")
|
||||||
|
|
||||||
|
# Save rbx and rbp
|
||||||
|
lines.append("\tpush rbx")
|
||||||
|
lines.append("\tpush rbp")
|
||||||
|
|
||||||
|
# Stash host stack in r10
|
||||||
|
lines.append("\tmov r10, rsp")
|
||||||
|
|
||||||
|
# Get current TEB
|
||||||
|
lines.append("\tmov rcx, fs:[currentThreadTeb@tpoff]")
|
||||||
|
|
||||||
|
# Save FS base
|
||||||
|
lines.append("\trdfsbase r9")
|
||||||
|
lines.append("\tmov qword ptr [rcx+TEB_FSBASE], r9")
|
||||||
|
|
||||||
|
# Save RSP and load guest stack
|
||||||
|
lines.append("\tmov rbp, qword ptr [rcx+TEB_SP]")
|
||||||
|
lines.append("\tmov qword ptr [rcx+TEB_SP], rsp")
|
||||||
|
lines.append("\tmov rsp, rbp")
|
||||||
|
|
||||||
|
# Allocate stack space for arguments
|
||||||
|
if target_layout.stack_size > 0:
|
||||||
|
lines.append(f"\tsub rsp, {target_layout.stack_size}")
|
||||||
|
|
||||||
|
# Align stack if needed (must be done after allocating args)
|
||||||
|
if align > 0:
|
||||||
|
lines.append(f"\tand rsp, ~{align - 1}")
|
||||||
|
|
||||||
|
# Transfer arguments
|
||||||
|
for i, target in enumerate(target_layout.args):
|
||||||
|
if target.stack_offset is None:
|
||||||
|
raise NotImplementedError(f"Unexpected register argument {target}")
|
||||||
|
|
||||||
|
source = source_layout.args[i]
|
||||||
|
if source.stack_offset is not None:
|
||||||
|
ptr_type = _x64_ptr_type_by_slot_size(source.slot_size)
|
||||||
|
register = _x64_register_by_slot_size("rax", target.slot_size)
|
||||||
|
lines.append(
|
||||||
|
f"\tmov {register}, {ptr_type} [r10+{source.stack_offset}]"
|
||||||
|
)
|
||||||
|
ptr_type = _x64_ptr_type_by_slot_size(target.slot_size)
|
||||||
|
register = _x64_register_by_slot_size("rax", target.slot_size)
|
||||||
|
elif source.register is not None:
|
||||||
|
ptr_type = _x64_ptr_type_by_slot_size(target.slot_size)
|
||||||
|
register = _x64_register_by_slot_size(source.register, target.slot_size)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Argument {i} is not a register or stack offset")
|
||||||
|
lines.append(f"\tmov {ptr_type} [rsp+{target.stack_offset}], {register}")
|
||||||
|
|
||||||
|
# Jump to 32-bit mode
|
||||||
|
lines.append("\tLJMP32")
|
||||||
|
|
||||||
|
# Setup FS selector
|
||||||
|
lines.append("\tmov ax, word ptr [ecx+TEB_FS_SEL]")
|
||||||
|
lines.append("\tmov fs, ax")
|
||||||
|
|
||||||
|
# Call into target
|
||||||
|
lines.append(f"\tcall {call_target}")
|
||||||
|
|
||||||
|
# Get current TEB
|
||||||
|
lines.append("\tmov ecx, fs:[TEB_SELF]")
|
||||||
|
|
||||||
|
# Jump back to 64-bit
|
||||||
|
lines.append("\tLJMP64")
|
||||||
|
|
||||||
|
# Sign extend return value if necessary
|
||||||
|
if f.return_type.sign_extended:
|
||||||
|
lines.append("\tcdqe")
|
||||||
|
|
||||||
|
# Restore FS base
|
||||||
|
lines.append("\tmov r9, qword ptr [rcx+TEB_FSBASE]")
|
||||||
|
lines.append("\twrfsbase r9")
|
||||||
|
|
||||||
|
# Restore host stack
|
||||||
|
lines.append("\tmov rsp, qword ptr [rcx+TEB_SP]")
|
||||||
|
lines.append("\tmov qword ptr [rcx+TEB_SP], rbp")
|
||||||
|
|
||||||
|
# Restore rbp, rbx and return
|
||||||
|
lines.append("\tpop rbp")
|
||||||
|
lines.append("\tpop rbx")
|
||||||
|
lines.append("\tret")
|
||||||
|
else:
|
||||||
|
lines.append(".code32")
|
||||||
|
|
||||||
|
# Save registers
|
||||||
|
lines.append("\tpush ebp")
|
||||||
|
lines.append("\tpush esi")
|
||||||
|
lines.append("\tpush edi")
|
||||||
|
|
||||||
|
# Get current TEB
|
||||||
|
lines.append("\tmov ecx, fs:[TEB_SELF]")
|
||||||
|
|
||||||
|
# Save fs segment
|
||||||
|
lines.append("\tmov di, fs")
|
||||||
|
lines.append("\tmov word ptr [ecx+TEB_FS_SEL], di")
|
||||||
|
|
||||||
|
# Jump back to 64-bit
|
||||||
|
lines.append("\tLJMP64")
|
||||||
|
|
||||||
|
# Restore FS base
|
||||||
|
lines.append("\tmov r9, qword ptr [rcx+TEB_FSBASE]")
|
||||||
|
lines.append("\twrfsbase r9")
|
||||||
|
|
||||||
|
# Stash guest stack in r10
|
||||||
|
lines.append("\tmov r10, rsp")
|
||||||
|
|
||||||
|
# Restore host stack
|
||||||
|
lines.append("\tmov rbp, qword ptr [rcx+TEB_SP]")
|
||||||
|
lines.append("\tmov qword ptr [rcx+TEB_SP], rsp")
|
||||||
|
lines.append("\tmov rsp, rbp")
|
||||||
|
|
||||||
|
# Allocate stack space for arguments
|
||||||
|
if target_layout.stack_size > 0:
|
||||||
|
lines.append(f"\tsub rsp, {target_layout.stack_size}")
|
||||||
|
|
||||||
|
# Align stack if needed (must be done after allocating args)
|
||||||
|
if align > 0:
|
||||||
|
lines.append(f"\tand rsp, ~{align - 1}")
|
||||||
|
|
||||||
|
# Transfer args
|
||||||
|
for i, target in enumerate(target_layout.args):
|
||||||
|
arg = f.args[i]
|
||||||
|
source = source_layout.args[i]
|
||||||
|
|
||||||
|
if target.stack_offset is not None:
|
||||||
|
if source.stack_offset is not None:
|
||||||
|
ptr_type = _x64_ptr_type_by_slot_size(source.slot_size)
|
||||||
|
register = _x64_register_by_slot_size("rax", source.slot_size)
|
||||||
|
lines.append(
|
||||||
|
f"\tmov {register}, {ptr_type} [r10+{source.stack_offset}]"
|
||||||
|
)
|
||||||
|
ptr_type = _x64_ptr_type_by_slot_size(target.slot_size)
|
||||||
|
register = _x64_register_by_slot_size("rax", target.slot_size)
|
||||||
|
elif source.register is not None:
|
||||||
|
ptr_type = _x64_ptr_type_by_slot_size(target.slot_size)
|
||||||
|
register = _x64_register_by_slot_size(
|
||||||
|
source.register, target.slot_size
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Argument {i} is not a register or stack offset")
|
||||||
|
lines.append(
|
||||||
|
f"\tmov {ptr_type} [rsp+{target.stack_offset}], {register}"
|
||||||
|
)
|
||||||
|
elif target.register is not None:
|
||||||
|
ptr_type = _x64_ptr_type_by_slot_size(source.slot_size)
|
||||||
|
if source.slot_size == 4 and target.slot_size == 8:
|
||||||
|
if arg.sign_extended:
|
||||||
|
register = _x64_register_by_slot_size(
|
||||||
|
target.register, source.slot_size
|
||||||
|
)
|
||||||
|
lines.append(
|
||||||
|
f"\tmov {register}, {ptr_type} [r10+{source.stack_offset}]"
|
||||||
|
)
|
||||||
|
lines.append(f"\tmovsxd {target.register}, {register}")
|
||||||
|
else:
|
||||||
|
register = _x64_register_by_slot_size(
|
||||||
|
target.register, source.slot_size
|
||||||
|
)
|
||||||
|
lines.append(
|
||||||
|
f"\tmov {register}, {ptr_type} [r10+{source.stack_offset}]"
|
||||||
|
)
|
||||||
|
elif source.slot_size == 8 and target.slot_size == 8:
|
||||||
|
lines.append(
|
||||||
|
f"\tmov {target.register}, {ptr_type} [r10+{source.stack_offset}]"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
raise NotImplementedError(
|
||||||
|
f"Unsupported conversion from {source.slot_size} to {target.slot_size}"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Call into target
|
||||||
|
lines.append(f"\tcall {call_target}")
|
||||||
|
|
||||||
|
# Get current TEB
|
||||||
|
lines.append("\tmov rcx, fs:[currentThreadTeb@tpoff]")
|
||||||
|
|
||||||
|
# Restore host stack
|
||||||
|
lines.append("\tmov rsp, qword ptr [rcx+TEB_SP]")
|
||||||
|
lines.append("\tmov qword ptr [rcx+TEB_SP], rbp")
|
||||||
|
|
||||||
|
# Jump to 32-bit mode
|
||||||
|
lines.append("\tLJMP32")
|
||||||
|
|
||||||
|
# Setup FS selector
|
||||||
|
lines.append("\tmov di, word ptr [ecx+TEB_FS_SEL]")
|
||||||
|
lines.append("\tmov fs, di")
|
||||||
|
|
||||||
|
# Restore registers
|
||||||
|
lines.append("\tpop edi")
|
||||||
|
lines.append("\tpop esi")
|
||||||
|
lines.append("\tpop ebp")
|
||||||
|
|
||||||
|
# Return to guest
|
||||||
|
if f.source_cc == CallingConv.X86_STDCALL and source_layout.stack_size > 0:
|
||||||
|
lines.append(f"\tret {source_layout.stack_size}")
|
||||||
|
else:
|
||||||
|
lines.append("\tret")
|
||||||
|
|
||||||
|
|
||||||
|
def emit_cc_thunk(f: FuncInfo | TypedefInfo, lines: List[str], arch: Arch):
|
||||||
|
if arch == Arch.X86_64:
|
||||||
|
return emit_cc_thunk64(f, lines)
|
||||||
|
elif arch == Arch.X86:
|
||||||
|
return emit_cc_thunk32(f, lines)
|
||||||
|
|
||||||
|
|
||||||
def emit_guest_to_host_thunks(
|
def emit_guest_to_host_thunks(
|
||||||
lines: List[str], dll: str, funcs: Iterable[FuncInfo]
|
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"thunk_{dll}_{f.name}"
|
||||||
@@ -545,19 +923,24 @@ def emit_guest_to_host_thunks(
|
|||||||
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})"
|
||||||
)
|
)
|
||||||
|
source_layout = compute_arg_layout(f.args, f.source_cc, Arch.X86)
|
||||||
|
target_layout = compute_arg_layout(f.args, f.target_cc, arch)
|
||||||
for i, arg in enumerate(f.args):
|
for i, arg in enumerate(f.args):
|
||||||
lines.append(
|
details: List[str] = []
|
||||||
f"\t# Arg {i} (slot_size={arg.slot_size}, primitive={arg.primitive}, sign_extended={arg.sign_extended})"
|
details.append(f"src={describe_arg_placement(source_layout.args[i])}")
|
||||||
)
|
details.append(f"dst={describe_arg_placement(target_layout.args[i])}")
|
||||||
|
details.append(f"class={arg.arg_class.value}")
|
||||||
|
details.append(f"sign_extended={arg.sign_extended}")
|
||||||
|
lines.append(f"\t# Arg {i} ({', '.join(details)})")
|
||||||
lines.append(f".globl {thunk}")
|
lines.append(f".globl {thunk}")
|
||||||
lines.append(f".type {thunk}, @function")
|
lines.append(f".type {thunk}, @function")
|
||||||
lines.append(f"{thunk}:")
|
lines.append(f"{thunk}:")
|
||||||
emit_cc_thunk(f, lines)
|
emit_cc_thunk(f, lines, arch)
|
||||||
lines.append(f".size {thunk}, .-{thunk}")
|
lines.append(f".size {thunk}, .-{thunk}")
|
||||||
|
|
||||||
|
|
||||||
def emit_host_to_guest_thunks(
|
def emit_host_to_guest_thunks(
|
||||||
lines: List[str], typedefs: Iterable[TypedefInfo]
|
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"call_{f.name}"
|
||||||
@@ -565,14 +948,23 @@ def emit_host_to_guest_thunks(
|
|||||||
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})"
|
||||||
)
|
)
|
||||||
|
source_layout = compute_arg_layout(f.args, f.source_cc, arch, skip_args=1)
|
||||||
|
target_layout = compute_arg_layout(f.args, f.target_cc, Arch.X86)
|
||||||
for i, arg in enumerate(f.args):
|
for i, arg in enumerate(f.args):
|
||||||
lines.append(
|
details: List[str] = []
|
||||||
f"\t# Arg {i} (slot_size={arg.slot_size}, primitive={arg.primitive}, sign_extended={arg.sign_extended})"
|
details.append(f"src={describe_arg_placement(source_layout.args[i])}")
|
||||||
)
|
details.append(f"dst={describe_arg_placement(target_layout.args[i])}")
|
||||||
|
details.append(f"class={arg.arg_class.value}")
|
||||||
|
details.append(f"sign_extended={arg.sign_extended}")
|
||||||
|
lines.append(f"\t# Arg {i} ({', '.join(details)})")
|
||||||
|
# details = []
|
||||||
|
# details.append(f"class={f.return_type.arg_class.value}")
|
||||||
|
# details.append(f"sign_extended={f.return_type.sign_extended}")
|
||||||
|
# lines.append(f"\t# Ret ({', '.join(details)})")
|
||||||
lines.append(f".weak {thunk}")
|
lines.append(f".weak {thunk}")
|
||||||
lines.append(f".type {thunk}, @function")
|
lines.append(f".type {thunk}, @function")
|
||||||
lines.append(f"{thunk}:")
|
lines.append(f"{thunk}:")
|
||||||
emit_cc_thunk(f, lines)
|
emit_cc_thunk(f, lines, arch)
|
||||||
lines.append(f".size {thunk}, .-{thunk}")
|
lines.append(f".size {thunk}, .-{thunk}")
|
||||||
|
|
||||||
|
|
||||||
@@ -581,6 +973,7 @@ def emit_header_mapping(
|
|||||||
funcs: Iterable[FuncInfo],
|
funcs: Iterable[FuncInfo],
|
||||||
typedefs: Iterable[TypedefInfo],
|
typedefs: Iterable[TypedefInfo],
|
||||||
variables: Iterable[VarInfo],
|
variables: Iterable[VarInfo],
|
||||||
|
arch: Arch,
|
||||||
) -> str:
|
) -> str:
|
||||||
guard = f"WIBO_GEN_{dll.upper()}_THUNKS_H"
|
guard = f"WIBO_GEN_{dll.upper()}_THUNKS_H"
|
||||||
lines: List[str] = []
|
lines: List[str] = []
|
||||||
@@ -619,16 +1012,18 @@ def emit_header_mapping(
|
|||||||
type_str = _canonical_type_str(arg.type)
|
type_str = _canonical_type_str(arg.type)
|
||||||
args.append(f"{type_str} arg{i}")
|
args.append(f"{type_str} arg{i}")
|
||||||
param_list = ", ".join(args)
|
param_list = ", ".join(args)
|
||||||
return_type = _canonical_type_str(f.return_type)
|
return_type = _canonical_type_str(f.return_type.type)
|
||||||
if f.source_cc == CallingConv.X86_STDCALL:
|
if arch == Arch.X86_64:
|
||||||
cc_attr = "__attribute__((stdcall))"
|
cc_attr = ""
|
||||||
|
elif f.source_cc == CallingConv.X86_STDCALL:
|
||||||
|
cc_attr = "__attribute__((stdcall)) "
|
||||||
elif f.source_cc == CallingConv.C:
|
elif f.source_cc == CallingConv.C:
|
||||||
cc_attr = "__attribute__((cdecl))"
|
cc_attr = "__attribute__((cdecl)) "
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError(
|
raise NotImplementedError(
|
||||||
f"Unsupported calling convention {f.source_cc.name} for function {f.name}"
|
f"Unsupported calling convention {f.source_cc.name} for function {f.name}"
|
||||||
)
|
)
|
||||||
lines.append(f"{cc_attr} {return_type} {thunk}({param_list});")
|
lines.append(f"{cc_attr}{return_type} {thunk}({param_list});")
|
||||||
|
|
||||||
# Host-to-guest thunk functions
|
# Host-to-guest thunk functions
|
||||||
for td in typedefs:
|
for td in typedefs:
|
||||||
@@ -642,7 +1037,7 @@ def emit_header_mapping(
|
|||||||
params.append(f"{type_str} arg{i}")
|
params.append(f"{type_str} arg{i}")
|
||||||
|
|
||||||
param_list = ", ".join(params)
|
param_list = ", ".join(params)
|
||||||
return_type = _type_to_string(td.return_type)
|
return_type = _type_to_string(td.return_type.type)
|
||||||
lines.append(f"{return_type} {thunk}({param_list});")
|
lines.append(f"{return_type} {thunk}({param_list});")
|
||||||
|
|
||||||
lines.append("#ifdef __cplusplus\n}\n#endif")
|
lines.append("#ifdef __cplusplus\n}\n#endif")
|
||||||
@@ -672,7 +1067,7 @@ def main() -> int:
|
|||||||
ap.add_argument(
|
ap.add_argument(
|
||||||
"--namespace", dest="ns", default=None, help="Namespace filter, e.g. kernel32"
|
"--namespace", dest="ns", default=None, help="Namespace filter, e.g. kernel32"
|
||||||
)
|
)
|
||||||
ap.add_argument("--arch", choices=["x86"], default="x86")
|
ap.add_argument("--arch", choices=["x86", "x86_64"], default="x86")
|
||||||
ap.add_argument(
|
ap.add_argument(
|
||||||
"--out-asm", type=Path, required=True, help="Output assembly file (.S)"
|
"--out-asm", type=Path, required=True, help="Output assembly file (.S)"
|
||||||
)
|
)
|
||||||
@@ -682,10 +1077,17 @@ def main() -> int:
|
|||||||
ap.add_argument("-I", dest="incs", action="append", default=[])
|
ap.add_argument("-I", dest="incs", action="append", default=[])
|
||||||
args = ap.parse_args()
|
args = ap.parse_args()
|
||||||
|
|
||||||
|
if args.arch == "x86":
|
||||||
|
arch = Arch.X86
|
||||||
|
elif args.arch == "x86_64":
|
||||||
|
arch = Arch.X86_64
|
||||||
|
else:
|
||||||
|
raise ValueError(f"Unsupported architecture: {args.arch}")
|
||||||
|
|
||||||
target = "i686-pc-linux-gnu" if args.arch == "x86" else "x86_64-pc-linux-gnu"
|
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)
|
funcs = collect_functions(tu, args.ns, arch)
|
||||||
typedefs = collect_typedefs(tu)
|
typedefs = collect_typedefs(tu, arch)
|
||||||
variables = collect_variables(tu, args.ns)
|
variables = collect_variables(tu, args.ns)
|
||||||
|
|
||||||
if not funcs and not typedefs and not variables:
|
if not funcs and not typedefs and not variables:
|
||||||
@@ -694,15 +1096,15 @@ 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(".intel_syntax noprefix")
|
lines.append('#include "macros.S"')
|
||||||
lines.append('.section .note.GNU-stack, "", @progbits')
|
lines.append('.section .note.GNU-stack, "", @progbits')
|
||||||
lines.append(".text")
|
lines.append(".text")
|
||||||
|
|
||||||
emit_guest_to_host_thunks(lines, args.dll, funcs)
|
emit_guest_to_host_thunks(lines, args.dll, funcs, arch)
|
||||||
emit_host_to_guest_thunks(lines, typedefs)
|
emit_host_to_guest_thunks(lines, typedefs, arch)
|
||||||
|
|
||||||
asm = "\n".join(lines) + "\n"
|
asm = "\n".join(lines) + "\n"
|
||||||
hdr = emit_header_mapping(args.dll, funcs, typedefs, variables)
|
hdr = emit_header_mapping(args.dll, funcs, typedefs, variables, arch)
|
||||||
|
|
||||||
args.out_asm.parent.mkdir(parents=True, exist_ok=True)
|
args.out_asm.parent.mkdir(parents=True, exist_ok=True)
|
||||||
args.out_hdr.parent.mkdir(parents=True, exist_ok=True)
|
args.out_hdr.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|||||||
Reference in New Issue
Block a user