Experimental 64-bit host support

This commit is contained in:
2025-11-04 22:07:51 -07:00
parent 463686d01a
commit 3dd9fb77ff
64 changed files with 1993 additions and 844 deletions

View File

@@ -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

View File

@@ -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
}
} }
] ]
} }

View File

@@ -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;

View File

@@ -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,12 +223,12 @@ 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,
@@ -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;
@@ -425,10 +428,10 @@ 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;
} }
@@ -446,9 +449,9 @@ 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;

View File

@@ -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,7 +85,7 @@ 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);
@@ -95,7 +95,7 @@ BOOL WINAPI DuplicateTokenEx(HANDLE hExistingToken, DWORD dwDesiredAccess, void
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);

View File

@@ -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;

View File

@@ -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);

View File

@@ -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;

View File

@@ -34,11 +34,9 @@ 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,

View File

@@ -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)

View File

@@ -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);

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
}; };

View File

@@ -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);

View File

@@ -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());

View File

@@ -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);
} }

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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;
} }

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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;
} }

View File

@@ -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;

View File

@@ -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);
@@ -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);
@@ -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);
@@ -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;
} }

View File

@@ -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);

View File

@@ -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;
} }

View File

@@ -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

View File

@@ -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) {

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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;
} }

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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, &regionSize, 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;
} }

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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;
} }

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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

View File

@@ -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;
} }
} }

View File

@@ -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
} }

View File

@@ -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]);
} }
} }

View File

@@ -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

View File

@@ -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
View 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__

View File

@@ -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;
} }

View File

@@ -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 &reg, 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) {

View File

@@ -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
View 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
View 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

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View 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}"
) )
target_layout = compute_arg_layout(f.args, f.target_cc, Arch.X86)
# Bytes we will push for the call (exclude args passed in registers) # Get current TEB
stack_bytes = sum(
arg.slot_size for i, arg in enumerate(f.args) if i not in reg_indices
)
# Get current TIB
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,8 +1012,10 @@ 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 = ""
elif f.source_cc == CallingConv.X86_STDCALL:
cc_attr = "__attribute__((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)) "
@@ -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)