diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c index f5ff845b1ee..d3840c323d7 100644 --- a/dlls/ntdll/exception.c +++ b/dlls/ntdll/exception.c @@ -640,15 +640,9 @@ RUNTIME_FUNCTION *lookup_function_info( ULONG_PTR pc, ULONG_PTR *base, LDR_DATA_ ULONG size; /* PE module or wine module */ - if (!LdrFindEntryForAddress( (void *)pc, module )) + if ((func = RtlLookupFunctionTable( pc, base, &size ))) { - *base = (ULONG_PTR)(*module)->DllBase; - if ((func = RtlImageDirectoryEntryToData( (*module)->DllBase, TRUE, - IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size ))) - { - /* lookup in function table */ - func = find_function_info( pc, (ULONG_PTR)(*module)->DllBase, func, size/sizeof(*func) ); - } + func = find_function_info( pc, (ULONG_PTR)(*module)->DllBase, func, size/sizeof(*func) ); } else { diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index 64fdb6fdb24..ccd270fee95 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -878,6 +878,7 @@ @ stdcall RtlLookupElementGenericTable(ptr ptr) # @ stub RtlLookupElementGenericTableAvl @ stdcall -arch=!i386 RtlLookupFunctionEntry(long ptr ptr) +@ stdcall -arch=!i386 RtlLookupFunctionTable(long ptr ptr) @ stdcall RtlMakeSelfRelativeSD(ptr ptr ptr) @ stdcall RtlMapGenericMask(ptr ptr) # @ stub RtlMapSecurityErrorToNtStatus diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c index 7a6c71927f6..f34d7751b60 100644 --- a/dlls/ntdll/signal_arm.c +++ b/dlls/ntdll/signal_arm.c @@ -1191,6 +1191,19 @@ PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG_PTR base, ULONG_PTR pc, } +/********************************************************************** + * RtlLookupFunctionTable (NTDLL.@) + */ +PRUNTIME_FUNCTION WINAPI RtlLookupFunctionTable( ULONG_PTR pc, ULONG_PTR *base, ULONG *len ) +{ + LDR_DATA_TABLE_ENTRY *module; + + if (LdrFindEntryForAddress( (void *)pc, &module )) return NULL; + *base = (ULONG_PTR)module->DllBase; + return RtlImageDirectoryEntryToData( module->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, len ); +} + + /********************************************************************** * call_consolidate_callback * diff --git a/dlls/ntdll/signal_arm64.c b/dlls/ntdll/signal_arm64.c index 9e2431a6b33..68506527b26 100644 --- a/dlls/ntdll/signal_arm64.c +++ b/dlls/ntdll/signal_arm64.c @@ -1070,6 +1070,20 @@ PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG_PTR base, ULONG_PTR pc, return handler; } + +/********************************************************************** + * RtlLookupFunctionTable (NTDLL.@) + */ +PRUNTIME_FUNCTION WINAPI RtlLookupFunctionTable( ULONG_PTR pc, ULONG_PTR *base, ULONG *len ) +{ + LDR_DATA_TABLE_ENTRY *module; + + if (LdrFindEntryForAddress( (void *)pc, &module )) return NULL; + *base = (ULONG_PTR)module->DllBase; + return RtlImageDirectoryEntryToData( module->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, len ); +} + + /********************************************************************** * call_consolidate_callback * diff --git a/dlls/ntdll/signal_arm64ec.c b/dlls/ntdll/signal_arm64ec.c index 8b4fd399c09..dc95bef4cb5 100644 --- a/dlls/ntdll/signal_arm64ec.c +++ b/dlls/ntdll/signal_arm64ec.c @@ -1782,6 +1782,35 @@ PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc, } +/********************************************************************** + * RtlLookupFunctionTable (NTDLL.@) + */ +PRUNTIME_FUNCTION WINAPI RtlLookupFunctionTable( ULONG_PTR pc, ULONG_PTR *base, ULONG *len ) +{ + LDR_DATA_TABLE_ENTRY *module; + + if (LdrFindEntryForAddress( (void *)pc, &module )) return NULL; + *base = (ULONG_PTR)module->DllBase; + + if (RtlIsEcCode( (void *)pc )) + { + IMAGE_LOAD_CONFIG_DIRECTORY *cfg; + IMAGE_ARM64EC_METADATA *metadata; + ULONG size; + + if (!(cfg = RtlImageDirectoryEntryToData( module->DllBase, TRUE, + IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &size ))) + return NULL; + size = min( size, cfg->Size ); + if (size <= offsetof( IMAGE_LOAD_CONFIG_DIRECTORY, CHPEMetadataPointer )) return NULL; + metadata = (IMAGE_ARM64EC_METADATA *)cfg->CHPEMetadataPointer; + *len = metadata->ExtraRFETableSize; + return (RUNTIME_FUNCTION *)(*base + metadata->ExtraRFETable); + } + return RtlImageDirectoryEntryToData( module->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, len ); +} + + /******************************************************************* * RtlUnwindEx (NTDLL.@) */ diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index 998e09179b4..731d950b420 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -1029,6 +1029,20 @@ PVOID WINAPI RtlVirtualUnwind( ULONG type, ULONG64 base, ULONG64 pc, return (char *)base + handler_data->handler; } + +/********************************************************************** + * RtlLookupFunctionTable (NTDLL.@) + */ +PRUNTIME_FUNCTION WINAPI RtlLookupFunctionTable( ULONG_PTR pc, ULONG_PTR *base, ULONG *len ) +{ + LDR_DATA_TABLE_ENTRY *module; + + if (LdrFindEntryForAddress( (void *)pc, &module )) return NULL; + *base = (ULONG_PTR)module->DllBase; + return RtlImageDirectoryEntryToData( module->DllBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, len ); +} + + struct unwind_exception_frame { EXCEPTION_REGISTRATION_RECORD frame; diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index b6d22092a11..080d22c84df 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -187,6 +187,7 @@ typedef struct _UNWIND_INFO static BOOLEAN (CDECL *pRtlInstallFunctionTableCallback)(DWORD64, DWORD64, DWORD, PGET_RUNTIME_FUNCTION_CALLBACK, PVOID, PCWSTR); static PRUNTIME_FUNCTION (WINAPI *pRtlLookupFunctionEntry)(ULONG64, ULONG64*, UNWIND_HISTORY_TABLE*); +static PRUNTIME_FUNCTION (WINAPI *pRtlLookupFunctionTable)(ULONG64, ULONG64*, ULONG*); static DWORD (WINAPI *pRtlAddGrowableFunctionTable)(void**, RUNTIME_FUNCTION*, DWORD, DWORD, ULONG_PTR, ULONG_PTR); static void (WINAPI *pRtlGrowFunctionTable)(void*, DWORD); static void (WINAPI *pRtlDeleteGrowableFunctionTable)(void*); @@ -196,6 +197,7 @@ static VOID (CDECL *pRtlRestoreContext)(CONTEXT*, EXCEPTION_RECORD*); static NTSTATUS (WINAPI *pRtlWow64GetThreadContext)(HANDLE, WOW64_CONTEXT *); static NTSTATUS (WINAPI *pRtlWow64SetThreadContext)(HANDLE, const WOW64_CONTEXT *); static NTSTATUS (WINAPI *pRtlWow64GetCpuAreaInfo)(WOW64_CPURESERVED*,ULONG,WOW64_CPU_AREA_INFO*); +static NTSTATUS (WINAPI *pRtlGetNativeSystemInformation)(SYSTEM_INFORMATION_CLASS,void*,ULONG,ULONG*); static int (CDECL *p_setjmp)(_JUMP_BUFFER*); #endif @@ -2793,11 +2795,13 @@ static void test_dynamic_unwind(void) { static const int code_offset = 1024; char buf[2 * sizeof(RUNTIME_FUNCTION) + 4]; + SYSTEM_CPU_INFORMATION info; RUNTIME_FUNCTION *runtime_func, *func; ULONG_PTR table, base; - void *growable_table; + void *growable_table, *ptr; NTSTATUS status; DWORD count; + ULONG len, len2; if (!pRtlInstallFunctionTableCallback || !pRtlLookupFunctionEntry) { @@ -2976,7 +2980,46 @@ static void test_dynamic_unwind(void) ok( base == (ULONG_PTR)code_mem, "RtlLookupFunctionEntry returned invalid base, expected: %Ix, got: %Ix\n", (ULONG_PTR)code_mem, base ); + base = 0xdeadbeef; + func = pRtlLookupFunctionTable( (ULONG_PTR)code_mem + code_offset + 8, &base, &len ); + ok( func == NULL, "RtlLookupFunctionTable wrong table, got: %p\n", func ); + ok( base == 0xdeadbeef, "RtlLookupFunctionTable wrong base, got: %Ix\n", base ); + + base = 0xdeadbeef; + func = pRtlLookupFunctionTable( (ULONG_PTR)pRtlLookupFunctionEntry, &base, &len ); + ok( base == (ULONG_PTR)GetModuleHandleA("ntdll.dll"), + "RtlLookupFunctionTable wrong base, got: %Ix / %p\n", base, GetModuleHandleA("ntdll.dll") ); + ptr = RtlImageDirectoryEntryToData( (void *)base, TRUE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &len2 ); + ok( func == ptr, "RtlLookupFunctionTable wrong table, got: %p / %p\n", func, ptr ); + ok( len == len2, "RtlLookupFunctionTable wrong len, got: %lu / %lu\n", len, len2 ); + pRtlDeleteGrowableFunctionTable( growable_table ); + + if (pRtlGetNativeSystemInformation && + !pRtlGetNativeSystemInformation( SystemCpuInformation, &info, sizeof(info), &len ) && + info.ProcessorArchitecture == PROCESSOR_ARCHITECTURE_ARM64) + { + static const BYTE fast_forward[] = { 0x48, 0x8b, 0xc4, 0x48, 0x89, 0x58, 0x20, 0x55, 0x5d, 0xe9 }; + IMAGE_ARM64EC_METADATA *metadata; + + if (!memcmp( pRtlLookupFunctionEntry, fast_forward, sizeof(fast_forward) )) + { + ptr = (char *)pRtlLookupFunctionEntry + sizeof(fast_forward); + ptr = (char *)ptr + 4 + *(int *)ptr; + base = 0xdeadbeef; + func = pRtlLookupFunctionTable( (ULONG_PTR)ptr, &base, &len ); + ok( base == (ULONG_PTR)GetModuleHandleA("ntdll.dll"), + "RtlLookupFunctionTable wrong base, got: %Ix / %p\n", base, GetModuleHandleA("ntdll.dll") ); + ptr = RtlImageDirectoryEntryToData( (void *)base, TRUE, IMAGE_DIRECTORY_ENTRY_EXCEPTION, &len2 ); + ok( func != ptr, "RtlLookupFunctionTable wrong table, got: %p / %p\n", func, ptr ); + ptr = RtlImageDirectoryEntryToData( (void *)base, TRUE, IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG, &len2 ); + metadata = (void *)((IMAGE_LOAD_CONFIG_DIRECTORY *)ptr)->CHPEMetadataPointer; + ok( (char *)func == (char *)base + metadata->ExtraRFETable, + "RtlLookupFunctonTable wrong table, got: %p / %p\n", func, (char *)base + metadata->ExtraRFETable ); + ok( len == metadata->ExtraRFETableSize, "RtlLookupFunctionTable wrong len, got: %lu / %lu\n", + len, metadata->ExtraRFETableSize ); + } + } } static int termination_handler_called; @@ -13006,6 +13049,7 @@ START_TEST(exception) #define X(f) p##f = (void*)GetProcAddress(hntdll, #f) X(RtlInstallFunctionTableCallback); X(RtlLookupFunctionEntry); + X(RtlLookupFunctionTable); X(RtlAddGrowableFunctionTable); X(RtlGrowFunctionTable); X(RtlDeleteGrowableFunctionTable); @@ -13015,6 +13059,7 @@ START_TEST(exception) X(RtlWow64GetThreadContext); X(RtlWow64SetThreadContext); X(RtlWow64GetCpuAreaInfo); + X(RtlGetNativeSystemInformation); #undef X p_setjmp = (void *)GetProcAddress( hmsvcrt, "_setjmp" ); diff --git a/include/winnt.h b/include/winnt.h index 0e0d1cb5170..2dc4eeb69d4 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -2074,6 +2074,7 @@ NTSYSAPI void WINAPI RtlDeleteGrowableFunctionTable(void*); NTSYSAPI void WINAPI RtlGrowFunctionTable(void*,DWORD); NTSYSAPI BOOLEAN CDECL RtlInstallFunctionTableCallback(DWORD_PTR,DWORD_PTR,DWORD,PGET_RUNTIME_FUNCTION_CALLBACK,PVOID,PCWSTR); NTSYSAPI PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry(DWORD_PTR,DWORD_PTR*,UNWIND_HISTORY_TABLE*); +NTSYSAPI PRUNTIME_FUNCTION WINAPI RtlLookupFunctionTable(DWORD_PTR,DWORD_PTR*,ULONG*); NTSYSAPI void WINAPI RtlUnwindEx(PVOID,PVOID,struct _EXCEPTION_RECORD*,PVOID,CONTEXT*,UNWIND_HISTORY_TABLE*); NTSYSAPI PVOID WINAPI RtlVirtualUnwind(DWORD,ULONG_PTR,ULONG_PTR,RUNTIME_FUNCTION*,CONTEXT*,PVOID*,ULONG_PTR*,KNONVOLATILE_CONTEXT_POINTERS*);