From 215a8e68d35bfe55bc8dc203deb6e73d6f215a0f Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 13 Feb 2024 11:25:43 +0100 Subject: [PATCH] ntdll: Move RtlLookupFunctionEntry() to the CPU backends. --- dlls/ntdll/exception.c | 93 +++++++++++++----------------------- dlls/ntdll/ntdll_misc.h | 3 +- dlls/ntdll/signal_arm.c | 74 +++++++++++++--------------- dlls/ntdll/signal_arm64.c | 36 ++++++++++---- dlls/ntdll/signal_arm64ec.c | 25 ++++++++++ dlls/ntdll/signal_x86_64.c | 32 +++++++++++-- dlls/ntdll/tests/exception.c | 5 ++ 7 files changed, 155 insertions(+), 113 deletions(-) diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c index d3840c323d7..935b57b36b9 100644 --- a/dlls/ntdll/exception.c +++ b/dlls/ntdll/exception.c @@ -595,9 +595,41 @@ BOOLEAN CDECL RtlDeleteFunctionTable( RUNTIME_FUNCTION *table ) } +/********************************************************************** + * lookup_dynamic_function_table + */ +RUNTIME_FUNCTION *lookup_dynamic_function_table( ULONG_PTR pc, ULONG_PTR *base, ULONG *count ) +{ + struct dynamic_unwind_entry *entry; + RUNTIME_FUNCTION *ret = NULL; + + RtlEnterCriticalSection( &dynamic_unwind_section ); + LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry ) + { + if (pc >= entry->base && pc < entry->end) + { + *base = entry->base; + if (entry->callback) + { + ret = entry->callback( pc, entry->context ); + *count = 1; + } + else + { + ret = entry->table; + *count = entry->count; + } + break; + } + } + RtlLeaveCriticalSection( &dynamic_unwind_section ); + return ret; +} + + /* helper for lookup_function_info() */ -static RUNTIME_FUNCTION *find_function_info( ULONG_PTR pc, ULONG_PTR base, - RUNTIME_FUNCTION *func, ULONG size ) +RUNTIME_FUNCTION *find_function_info( ULONG_PTR pc, ULONG_PTR base, + RUNTIME_FUNCTION *func, ULONG size ) { int min = 0; int max = size - 1; @@ -630,63 +662,6 @@ static RUNTIME_FUNCTION *find_function_info( ULONG_PTR pc, ULONG_PTR base, return NULL; } -/********************************************************************** - * lookup_function_info - */ -RUNTIME_FUNCTION *lookup_function_info( ULONG_PTR pc, ULONG_PTR *base, LDR_DATA_TABLE_ENTRY **module ) -{ - RUNTIME_FUNCTION *func = NULL; - struct dynamic_unwind_entry *entry; - ULONG size; - - /* PE module or wine module */ - if ((func = RtlLookupFunctionTable( pc, base, &size ))) - { - func = find_function_info( pc, (ULONG_PTR)(*module)->DllBase, func, size/sizeof(*func) ); - } - else - { - *module = NULL; - - RtlEnterCriticalSection( &dynamic_unwind_section ); - LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry ) - { - if (pc >= entry->base && pc < entry->end) - { - *base = entry->base; - /* use callback or lookup in function table */ - if (entry->callback) - func = entry->callback( pc, entry->context ); - else - func = find_function_info( pc, entry->base, entry->table, entry->count ); - break; - } - } - RtlLeaveCriticalSection( &dynamic_unwind_section ); - } - - return func; -} - -/********************************************************************** - * RtlLookupFunctionEntry (NTDLL.@) - */ -PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG_PTR pc, ULONG_PTR *base, - UNWIND_HISTORY_TABLE *table ) -{ - LDR_DATA_TABLE_ENTRY *module; - RUNTIME_FUNCTION *func; - - /* FIXME: should use the history table to make things faster */ - - if (!(func = lookup_function_info( pc, base, &module ))) - { - *base = 0; - WARN( "no exception table found for %Ix\n", pc ); - } - return func; -} - #endif /* __x86_64__ || __arm__ || __aarch64__ */ diff --git a/dlls/ntdll/ntdll_misc.h b/dlls/ntdll/ntdll_misc.h index 58e29837cd0..1aeed955bf4 100644 --- a/dlls/ntdll/ntdll_misc.h +++ b/dlls/ntdll/ntdll_misc.h @@ -85,7 +85,8 @@ extern void WINAPI KiUserCallbackDispatcherReturn(void); extern void (WINAPI *pWow64PrepareForException)( EXCEPTION_RECORD *rec, CONTEXT *context ); #if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__) -extern RUNTIME_FUNCTION *lookup_function_info( ULONG_PTR pc, ULONG_PTR *base, LDR_DATA_TABLE_ENTRY **module ); +extern RUNTIME_FUNCTION *lookup_dynamic_function_table( ULONG_PTR pc, ULONG_PTR *base, ULONG *count ); +extern RUNTIME_FUNCTION *find_function_info( ULONG_PTR pc, ULONG_PTR base, RUNTIME_FUNCTION *func, ULONG size ); #endif /* debug helpers */ diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c index 00ec7cd5626..76dac1b850c 100644 --- a/dlls/ntdll/signal_arm.c +++ b/dlls/ntdll/signal_arm.c @@ -117,7 +117,6 @@ __ASM_GLOBAL_FUNC( RtlCaptureContext, */ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEXT *context ) { - LDR_DATA_TABLE_ENTRY *module; NTSTATUS status; DWORD pc; @@ -128,57 +127,23 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX dispatch->ControlPcIsUnwound = (context->ContextFlags & CONTEXT_UNWOUND_TO_CALL) != 0; pc = context->Pc - (dispatch->ControlPcIsUnwound ? 2 : 0); - /* first look for PE exception information */ - - if ((dispatch->FunctionEntry = lookup_function_info(pc, - (ULONG_PTR*)&dispatch->ImageBase, &module ))) + if ((dispatch->FunctionEntry = RtlLookupFunctionEntry( pc, (DWORD_PTR *)&dispatch->ImageBase, + dispatch->HistoryTable ))) { dispatch->LanguageHandler = RtlVirtualUnwind( type, dispatch->ImageBase, pc, dispatch->FunctionEntry, context, - &dispatch->HandlerData, (ULONG_PTR *)&dispatch->EstablisherFrame, - NULL ); + &dispatch->HandlerData, + (ULONG_PTR *)&dispatch->EstablisherFrame, NULL ); return STATUS_SUCCESS; } - /* then look for host system exception information */ - - if (!module || (module->Flags & LDR_WINE_INTERNAL)) - { - struct unwind_builtin_dll_params params = { type, dispatch, context }; - - status = WINE_UNIX_CALL( unix_unwind_builtin_dll, ¶ms ); - if (status != STATUS_SUCCESS) return status; - - if (dispatch->EstablisherFrame) - { - dispatch->FunctionEntry = NULL; - if (dispatch->LanguageHandler && !module) - { - FIXME( "calling personality routine in system library not supported yet\n" ); - dispatch->LanguageHandler = NULL; - } - return STATUS_SUCCESS; - } - } - else - { - status = context->Pc != context->Lr ? - STATUS_SUCCESS : STATUS_INVALID_DISPOSITION; - WARN( "exception data not found in %s for %p, LR %p, status %lx\n", - debugstr_w(module->BaseDllName.Buffer), (void*) context->Pc, - (void*) context->Lr, status ); - dispatch->EstablisherFrame = context->Sp; - dispatch->LanguageHandler = NULL; - context->Pc = context->Lr; - context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL; - return status; - } - + WARN( "exception data not found for pc %p, lr %p\n", (void *)context->Pc, (void *)context->Lr ); + status = context->Pc != context->Lr ? STATUS_SUCCESS : STATUS_INVALID_DISPOSITION; dispatch->EstablisherFrame = context->Sp; dispatch->LanguageHandler = NULL; context->Pc = context->Lr; context->ContextFlags |= CONTEXT_UNWOUND_TO_CALL; - return STATUS_SUCCESS; + return status; } @@ -1192,6 +1157,31 @@ PRUNTIME_FUNCTION WINAPI RtlLookupFunctionTable( ULONG_PTR pc, ULONG_PTR *base, } +/********************************************************************** + * RtlLookupFunctionEntry (NTDLL.@) + */ +PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG_PTR pc, ULONG_PTR *base, + UNWIND_HISTORY_TABLE *table ) +{ + RUNTIME_FUNCTION *func; + ULONG_PTR dynbase; + ULONG size; + + if ((func = RtlLookupFunctionTable( pc, base, &size ))) + return find_function_info( pc, *base, func, size / sizeof(*func)); + + if ((func = lookup_dynamic_function_table( pc, &dynbase, &size ))) + { + RUNTIME_FUNCTION *ret = find_function_info( pc, dynbase, func, size ); + if (ret) *base = dynbase; + return ret; + } + + *base = 0; + return NULL; +} + + /********************************************************************** * call_consolidate_callback * diff --git a/dlls/ntdll/signal_arm64.c b/dlls/ntdll/signal_arm64.c index 4c37204cfe1..cfb097bf7a2 100644 --- a/dlls/ntdll/signal_arm64.c +++ b/dlls/ntdll/signal_arm64.c @@ -148,7 +148,6 @@ __ASM_GLOBAL_FUNC( RtlCaptureContext, */ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEXT *context ) { - LDR_DATA_TABLE_ENTRY *module; NTSTATUS status; DWORD64 pc; @@ -159,7 +158,8 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX dispatch->ControlPcIsUnwound = (context->ContextFlags & CONTEXT_UNWOUND_TO_CALL) != 0; pc = context->Pc - (dispatch->ControlPcIsUnwound ? 4 : 0); - if ((dispatch->FunctionEntry = lookup_function_info( pc, &dispatch->ImageBase, &module ))) + if ((dispatch->FunctionEntry = RtlLookupFunctionEntry( pc, &dispatch->ImageBase, + dispatch->HistoryTable ))) { dispatch->LanguageHandler = RtlVirtualUnwind( type, dispatch->ImageBase, pc, dispatch->FunctionEntry, context, @@ -168,13 +168,8 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX return STATUS_SUCCESS; } + WARN( "exception data not found for pc %p, lr %p\n", (void *)context->Pc, (void *)context->Lr ); status = context->Pc != context->Lr ? STATUS_SUCCESS : STATUS_INVALID_DISPOSITION; - if (module) - WARN( "exception data not found in %s for pc %p, lr %p\n", - debugstr_w(module->BaseDllName.Buffer), (void *)context->Pc, (void *)context->Lr ); - else - WARN( "no module found for pc %p, lr %p\n", - (void *)context->Pc, (void *)context->Lr ); dispatch->EstablisherFrame = context->Sp; dispatch->LanguageHandler = NULL; context->Pc = context->Lr; @@ -1063,6 +1058,31 @@ PRUNTIME_FUNCTION WINAPI RtlLookupFunctionTable( ULONG_PTR pc, ULONG_PTR *base, } +/********************************************************************** + * RtlLookupFunctionEntry (NTDLL.@) + */ +PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG_PTR pc, ULONG_PTR *base, + UNWIND_HISTORY_TABLE *table ) +{ + RUNTIME_FUNCTION *func; + ULONG_PTR dynbase; + ULONG size; + + if ((func = RtlLookupFunctionTable( pc, base, &size ))) + return find_function_info( pc, *base, func, size / sizeof(*func)); + + if ((func = lookup_dynamic_function_table( pc, &dynbase, &size ))) + { + RUNTIME_FUNCTION *ret = find_function_info( pc, dynbase, func, size ); + if (ret) *base = dynbase; + return ret; + } + + *base = 0; + return NULL; +} + + /********************************************************************** * call_consolidate_callback * diff --git a/dlls/ntdll/signal_arm64ec.c b/dlls/ntdll/signal_arm64ec.c index dc95bef4cb5..4429bc4fcf9 100644 --- a/dlls/ntdll/signal_arm64ec.c +++ b/dlls/ntdll/signal_arm64ec.c @@ -1811,6 +1811,31 @@ PRUNTIME_FUNCTION WINAPI RtlLookupFunctionTable( ULONG_PTR pc, ULONG_PTR *base, } +/********************************************************************** + * RtlLookupFunctionEntry (NTDLL.@) + */ +PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG_PTR pc, ULONG_PTR *base, + UNWIND_HISTORY_TABLE *table ) +{ + RUNTIME_FUNCTION *func; + ULONG_PTR dynbase; + ULONG size; + + if ((func = RtlLookupFunctionTable( pc, base, &size ))) + return find_function_info( pc, *base, func, size / sizeof(*func)); + + if ((func = lookup_dynamic_function_table( pc, &dynbase, &size ))) + { + RUNTIME_FUNCTION *ret = find_function_info( pc, dynbase, func, size ); + if (ret) *base = dynbase; + return ret; + } + + *base = 0; + return NULL; +} + + /******************************************************************* * RtlUnwindEx (NTDLL.@) */ diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index 98a1ee9f063..09658eaa408 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -264,7 +264,8 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX /* first look for PE exception information */ - if ((dispatch->FunctionEntry = lookup_function_info( context->Rip, &dispatch->ImageBase, &module ))) + if ((dispatch->FunctionEntry = RtlLookupFunctionEntry( context->Rip, &dispatch->ImageBase, + dispatch->HistoryTable ))) { dispatch->LanguageHandler = RtlVirtualUnwind( type, dispatch->ImageBase, context->Rip, dispatch->FunctionEntry, context, @@ -275,7 +276,7 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX /* then look for host system exception information */ - if (!module || (module->Flags & LDR_WINE_INTERNAL)) + if (LdrFindEntryForAddress( (void *)context->Rip, &module ) || (module->Flags & LDR_WINE_INTERNAL)) { struct unwind_builtin_dll_params params = { type, dispatch, context }; @@ -287,10 +288,10 @@ static NTSTATUS virtual_unwind( ULONG type, DISPATCHER_CONTEXT *dispatch, CONTEX } if (status != STATUS_UNSUCCESSFUL) return status; } - else WARN( "exception data not found in %s\n", debugstr_w(module->BaseDllName.Buffer) ); /* no exception information, treat as a leaf function */ + WARN( "exception data not found for pc %p\n", (void *)context->Rip ); dispatch->EstablisherFrame = context->Rsp; dispatch->LanguageHandler = NULL; context->Rip = *(ULONG64 *)context->Rsp; @@ -1031,6 +1032,31 @@ PRUNTIME_FUNCTION WINAPI RtlLookupFunctionTable( ULONG_PTR pc, ULONG_PTR *base, } +/********************************************************************** + * RtlLookupFunctionEntry (NTDLL.@) + */ +PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG_PTR pc, ULONG_PTR *base, + UNWIND_HISTORY_TABLE *table ) +{ + RUNTIME_FUNCTION *func; + ULONG_PTR dynbase; + ULONG size; + + if ((func = RtlLookupFunctionTable( pc, base, &size ))) + return find_function_info( pc, *base, func, size / sizeof(*func)); + + if ((func = lookup_dynamic_function_table( pc, &dynbase, &size ))) + { + RUNTIME_FUNCTION *ret = find_function_info( pc, dynbase, func, size ); + if (ret) *base = dynbase; + return ret; + } + + *base = 0; + return NULL; +} + + struct unwind_exception_frame { EXCEPTION_REGISTRATION_RECORD frame; diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index dd34a76d5af..f01bb488a6a 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -2968,6 +2968,11 @@ 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 = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 32, &base, NULL ); + ok( func == NULL, "RtlLookupFunctionEntry got %p\n", func ); + ok( base == 0xdeadbeef, "RtlLookupFunctionTable wrong base, got: %Ix\n", base ); + base = 0xdeadbeef; func = pRtlLookupFunctionTable( (ULONG_PTR)code_mem + code_offset + 8, &base, &len ); ok( func == NULL, "RtlLookupFunctionTable wrong table, got: %p\n", func );