Module: wine Branch: master Commit: 1b63875c66c79a337f65c6c66882c8a55430d2c2 URL: https://source.winehq.org/git/wine.git/?a=commit;h=1b63875c66c79a337f65c6c66...
Author: Alexandre Julliard julliard@winehq.org Date: Thu Jul 22 13:42:56 2021 +0200
wow64: Add support for setting up the syscall table.
Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/wow64/syscall.c | 126 ++++++++++++++++++++++++++++++++++++++++++++- dlls/wow64/wow64_private.h | 5 ++ 2 files changed, 129 insertions(+), 2 deletions(-)
diff --git a/dlls/wow64/syscall.c b/dlls/wow64/syscall.c index 504580e8717..12e13b17574 100644 --- a/dlls/wow64/syscall.c +++ b/dlls/wow64/syscall.c @@ -35,6 +35,22 @@ WINE_DEFAULT_DEBUG_CHANNEL(wow); USHORT native_machine = 0; USHORT current_machine = 0;
+typedef NTSTATUS (WINAPI *syscall_thunk)( UINT *args ); + +static const syscall_thunk syscall_thunks[] = +{ + NULL +}; + +static const char *syscall_names[] = +{ + "" +}; + +static unsigned short syscall_map[1024]; + +static SYSTEM_DLL_INIT_BLOCK *pLdrSystemDllInitBlock; + void *dummy = RtlUnwind;
BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved ) @@ -58,6 +74,82 @@ void __cdecl __wine_spec_unimplemented_stub( const char *module, const char *fun }
+/********************************************************************** + * get_syscall_num + */ +static DWORD get_syscall_num( const BYTE *syscall ) +{ + DWORD id = ~0u; + + if (!syscall) return id; + switch (current_machine) + { + case IMAGE_FILE_MACHINE_I386: + if (syscall[0] == 0xb8 && syscall[5] == 0xba && syscall[10] == 0xff && syscall[11] == 0xd2) + id = *(DWORD *)(syscall + 1); + break; + + case IMAGE_FILE_MACHINE_ARM: + if (*(WORD *)syscall == 0xb40f) + { + DWORD inst = *(DWORD *)((WORD *)syscall + 1); + id = ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) + + ((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff); + } + break; + } + return id; +} + + +/********************************************************************** + * init_syscall_table + */ +static void init_syscall_table( HMODULE ntdll ) +{ + const IMAGE_EXPORT_DIRECTORY *exports; + const ULONG *functions, *names; + const USHORT *ordinals; + ULONG id, exp_size, exp_pos, wrap_pos; + + exports = RtlImageDirectoryEntryToData( ntdll, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size ); + ordinals = get_rva( ntdll, exports->AddressOfNameOrdinals ); + functions = get_rva( ntdll, exports->AddressOfFunctions ); + names = get_rva( ntdll, exports->AddressOfNames ); + + for (exp_pos = wrap_pos = 0; exp_pos < exports->NumberOfNames; exp_pos++) + { + char *name = get_rva( ntdll, names[exp_pos] ); + int res = -1; + + if (strncmp( name, "Nt", 2 ) && strncmp( name, "wine", 4 ) && strncmp( name, "__wine", 6 )) + continue; /* not a syscall */ + + if ((id = get_syscall_num( get_rva( ntdll, functions[ordinals[exp_pos]] ))) == ~0u) + continue; /* not a syscall */ + + if (wrap_pos < ARRAY_SIZE(syscall_names)) + res = strcmp( name, syscall_names[wrap_pos] ); + + if (!res) /* got a match */ + { + if (id < ARRAY_SIZE(syscall_map)) syscall_map[id] = wrap_pos++; + else ERR( "invalid syscall id %04x for %s\n", id, name ); + } + else if (res > 0) + { + FIXME( "no ntdll export for syscall %s\n", syscall_names[wrap_pos] ); + wrap_pos++; + exp_pos--; /* try again */ + } + else FIXME( "missing wrapper for syscall %04x %s\n", id, name ); + } + + for ( ; wrap_pos < ARRAY_SIZE(syscall_thunks); wrap_pos++) + FIXME( "no ntdll export for syscall %s\n", syscall_names[wrap_pos] ); +} + + /********************************************************************** * load_cpu_dll */ @@ -100,10 +192,24 @@ static HMODULE load_cpu_dll(void) */ static void process_init(void) { + HMODULE module; + UNICODE_STRING str; + RtlWow64GetProcessMachines( GetCurrentProcess(), ¤t_machine, &native_machine ); if (!current_machine) current_machine = native_machine;
+#define GET_PTR(name) p ## name = RtlFindExportedRoutineByName( module, #name ) + + RtlInitUnicodeString( &str, L"ntdll.dll" ); + LdrGetDllHandle( NULL, 0, &str, &module ); + GET_PTR( LdrSystemDllInitBlock ); + + module = (HMODULE)(ULONG_PTR)pLdrSystemDllInitBlock->ntdll_handle; + init_syscall_table( module ); + load_cpu_dll(); + +#undef GET_PTR }
@@ -112,8 +218,24 @@ static void process_init(void) */ NTSTATUS WINAPI Wow64SystemServiceEx( UINT num, UINT *args ) { - FIXME( "stub\n" ); - return STATUS_INVALID_SYSTEM_SERVICE; + NTSTATUS status; + + if (num >= ARRAY_SIZE( syscall_map ) || !syscall_map[num]) + { + ERR( "unsupported syscall %04x\n", num ); + return STATUS_INVALID_SYSTEM_SERVICE; + } + __TRY + { + syscall_thunk thunk = syscall_thunks[syscall_map[num]]; + status = thunk( args ); + } + __EXCEPT_ALL + { + status = GetExceptionCode(); + } + __ENDTRY; + return status; }
diff --git a/dlls/wow64/wow64_private.h b/dlls/wow64/wow64_private.h index 52cc40566b1..2c8f6f313fc 100644 --- a/dlls/wow64/wow64_private.h +++ b/dlls/wow64/wow64_private.h @@ -24,6 +24,11 @@ extern USHORT native_machine DECLSPEC_HIDDEN; extern USHORT current_machine DECLSPEC_HIDDEN;
+static inline void *get_rva( HMODULE module, DWORD va ) +{ + return (void *)((char *)module + va); +} + /* cf. GetSystemWow64Directory2 */ static inline const WCHAR *get_machine_wow64_dir( USHORT machine ) {