Add proper implementation for dynamic unwind functions, removed stub implementation.

This commit is contained in:
Sebastian Lackner 2014-04-04 19:46:13 +02:00
parent c781d177e1
commit 22a1e1ff59
6 changed files with 391 additions and 50 deletions

View File

@ -0,0 +1,189 @@
From 00e4f5ab76c745a28079c634dd9cf76456b81e22 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Fri, 4 Apr 2014 10:11:56 +0200
Subject: ntdll: Unify exception function lookup on x86_64.
---
dlls/ntdll/signal_x86_64.c | 102 +++++++++++++++++++++-----------------------
1 file changed, 48 insertions(+), 54 deletions(-)
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index b28cb99..57afe16 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -1921,6 +1921,28 @@ static RUNTIME_FUNCTION *find_function_info( ULONG64 pc, HMODULE module,
return NULL;
}
+/**********************************************************************
+ * lookup_function_info
+ */
+static RUNTIME_FUNCTION *lookup_function_info( ULONG64 pc, ULONG64 *base, LDR_MODULE **module )
+{
+ RUNTIME_FUNCTION *func = NULL;
+ ULONG size;
+
+ /* PE module or wine module */
+ if (!LdrFindEntryForAddress( (void *)pc, module ))
+ {
+ *base = (ULONG64)(*module)->BaseAddress;
+ if ((func = RtlImageDirectoryEntryToData( (*module)->BaseAddress, TRUE,
+ IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
+ {
+ /* lookup in function table */
+ func = find_function_info( pc, (*module)->BaseAddress, func, size );
+ }
+ }
+
+ return func;
+}
/**********************************************************************
* call_handler
@@ -2002,7 +2024,6 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_contex
DISPATCHER_CONTEXT dispatch;
CONTEXT context, new_context;
LDR_MODULE *module;
- DWORD size;
NTSTATUS status;
context = *orig_context;
@@ -2021,31 +2042,18 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_contex
/* first look for PE exception information */
- if (!LdrFindEntryForAddress( (void *)context.Rip, &module ))
+ if ((dispatch.FunctionEntry = lookup_function_info( context.Rip, &dispatch.ImageBase, &module )))
{
- RUNTIME_FUNCTION *dir;
-
- dispatch.ImageBase = (ULONG64)module->BaseAddress;
- if ((dir = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
- IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
- {
- if ((dispatch.FunctionEntry = find_function_info( context.Rip, module->BaseAddress,
- dir, size )))
- {
- dispatch.LanguageHandler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, dispatch.ImageBase,
- context.Rip, dispatch.FunctionEntry,
- &new_context, &dispatch.HandlerData,
- &dispatch.EstablisherFrame, NULL );
- goto unwind_done;
- }
- }
- else if (!(module->Flags & LDR_WINE_INTERNAL))
- WARN( "exception data not found in %s\n", debugstr_w(module->BaseDllName.Buffer) );
+ dispatch.LanguageHandler = RtlVirtualUnwind( UNW_FLAG_EHANDLER, dispatch.ImageBase,
+ context.Rip, dispatch.FunctionEntry,
+ &new_context, &dispatch.HandlerData,
+ &dispatch.EstablisherFrame, NULL );
+ goto unwind_done;
}
/* then look for host system exception information */
- if (!module || (module->Flags & LDR_WINE_INTERNAL))
+ else if (!module || (module->Flags & LDR_WINE_INTERNAL))
{
struct dwarf_eh_bases bases;
const struct dwarf_fde *fde = _Unwind_Find_FDE( (void *)(context.Rip - 1), &bases );
@@ -2065,6 +2073,8 @@ static NTSTATUS call_stack_handlers( EXCEPTION_RECORD *rec, CONTEXT *orig_contex
}
}
+ else WARN( "exception data not found in %s\n", debugstr_w(module->BaseDllName.Buffer) );
+
/* no exception information, treat as a leaf function */
new_context.Rip = *(ULONG64 *)context.Rsp;
@@ -2540,23 +2550,18 @@ PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG64 pc, ULONG64 *base, UNWI
{
LDR_MODULE *module;
RUNTIME_FUNCTION *func;
- ULONG size;
/* FIXME: should use the history table to make things faster */
- if (LdrFindEntryForAddress( (void *)pc, &module ))
+ func = lookup_function_info( pc, base, &module );
+ if (!func)
{
- WARN( "module not found for %lx\n", pc );
- return NULL;
- }
- if (!(func = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
- IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
- {
- WARN( "no exception table found in module %p pc %lx\n", module->BaseAddress, pc );
- return NULL;
+ if (module)
+ WARN( "no exception table found in module %p pc %lx\n", module->BaseAddress, pc );
+ else
+ WARN( "module not found for %lx\n", pc );
}
- func = find_function_info( pc, module->BaseAddress, func, size );
- if (func) *base = (ULONG64)module->BaseAddress;
+
return func;
}
@@ -2916,7 +2921,7 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
CONTEXT new_context;
LDR_MODULE *module;
NTSTATUS status;
- DWORD i, size;
+ DWORD i;
RtlCaptureContext( context );
new_context = *context;
@@ -2962,31 +2967,18 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
/* first look for PE exception information */
- if (!LdrFindEntryForAddress( (void *)context->Rip, &module ))
+ if ((dispatch.FunctionEntry = lookup_function_info( context->Rip, &dispatch.ImageBase, &module )))
{
- RUNTIME_FUNCTION *dir;
-
- dispatch.ImageBase = (ULONG64)module->BaseAddress;
- if ((dir = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
- IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
- {
- if ((dispatch.FunctionEntry = find_function_info( context->Rip, module->BaseAddress,
- dir, size )))
- {
- dispatch.LanguageHandler = RtlVirtualUnwind( UNW_FLAG_UHANDLER, dispatch.ImageBase,
- context->Rip, dispatch.FunctionEntry,
- &new_context, &dispatch.HandlerData,
- &dispatch.EstablisherFrame, NULL );
- goto unwind_done;
- }
- }
- else if (!(module->Flags & LDR_WINE_INTERNAL))
- WARN( "exception data not found in %s\n", debugstr_w(module->BaseDllName.Buffer) );
+ dispatch.LanguageHandler = RtlVirtualUnwind( UNW_FLAG_UHANDLER, dispatch.ImageBase,
+ context->Rip, dispatch.FunctionEntry,
+ &new_context, &dispatch.HandlerData,
+ &dispatch.EstablisherFrame, NULL );
+ goto unwind_done;
}
/* then look for host system exception information */
- if (!module || (module->Flags & LDR_WINE_INTERNAL))
+ else if (!module || (module->Flags & LDR_WINE_INTERNAL))
{
struct dwarf_eh_bases bases;
const struct dwarf_fde *fde = _Unwind_Find_FDE( (void *)(context->Rip - 1), &bases );
@@ -3006,6 +2998,8 @@ void WINAPI RtlUnwindEx( PVOID end_frame, PVOID target_ip, EXCEPTION_RECORD *rec
}
}
+ else WARN( "exception data not found in %s\n", debugstr_w(module->BaseDllName.Buffer) );
+
/* no exception information, treat as a leaf function */
new_context.Rip = *(ULONG64 *)context->Rsp;
--
1.7.9.5

View File

@ -0,0 +1,198 @@
From c9b382af632550740ec72f57a178c16f246d0ca5 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Fri, 4 Apr 2014 19:32:33 +0200
Subject: ntdll: Implement dynamic unwind table functions.
---
dlls/ntdll/ntdll.spec | 1 +
dlls/ntdll/signal_x86_64.c | 127 +++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 126 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 0dd75a2..7a3c3f1 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -689,6 +689,7 @@
# @ stub RtlInitializeStackTraceDataBase
@ stub RtlInsertElementGenericTable
# @ stub RtlInsertElementGenericTableAvl
+@ cdecl -arch=x86_64 RtlInstallFunctionTableCallback(long long long ptr ptr ptr)
@ stdcall RtlInt64ToUnicodeString(int64 long ptr)
@ stdcall RtlIntegerToChar(long long long ptr)
@ stdcall RtlIntegerToUnicodeString(long long ptr)
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index 57afe16..5ace5a9 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -56,6 +56,7 @@
#include "winternl.h"
#include "wine/library.h"
#include "wine/exception.h"
+#include "wine/list.h"
#include "ntdll_misc.h"
#include "wine/debug.h"
@@ -271,6 +272,34 @@ typedef int (*wine_signal_handler)(unsigned int sig);
static wine_signal_handler handlers[256];
+/***********************************************************************
+ * Dynamic unwind table
+ */
+
+struct dynamic_unwind_entry
+{
+ struct list entry;
+
+ DWORD64 base;
+ DWORD size;
+
+ RUNTIME_FUNCTION *table;
+ DWORD table_size;
+
+ PRUNTIME_FUNCTION (*callback)( DWORD pc, PVOID context );
+ PVOID context;
+};
+
+static struct list dynamic_unwind_list = LIST_INIT(dynamic_unwind_list);
+
+static RTL_CRITICAL_SECTION dynamic_unwind_section;
+static RTL_CRITICAL_SECTION_DEBUG dynamic_unwind_debug =
+{
+ 0, 0, &dynamic_unwind_section,
+ { &dynamic_unwind_debug.ProcessLocksList, &dynamic_unwind_debug.ProcessLocksList },
+ 0, 0, { (DWORD_PTR)(__FILE__ ": dynamic_unwind_section") }
+};
+static RTL_CRITICAL_SECTION dynamic_unwind_section = { &dynamic_unwind_debug, -1, 0, 0, 0, 0 };
/***********************************************************************
* Definitions for Win32 unwind tables
@@ -1927,6 +1956,7 @@ static RUNTIME_FUNCTION *find_function_info( ULONG64 pc, HMODULE module,
static RUNTIME_FUNCTION *lookup_function_info( ULONG64 pc, ULONG64 *base, LDR_MODULE **module )
{
RUNTIME_FUNCTION *func = NULL;
+ struct dynamic_unwind_entry *entry;
ULONG size;
/* PE module or wine module */
@@ -1940,6 +1970,25 @@ static RUNTIME_FUNCTION *lookup_function_info( ULONG64 pc, ULONG64 *base, LDR_MO
func = find_function_info( pc, (*module)->BaseAddress, func, size );
}
}
+ else
+ {
+ RtlEnterCriticalSection( &dynamic_unwind_section );
+ LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry )
+ {
+ if (pc >= entry->base && pc < entry->base + entry->size)
+ {
+ *base = entry->base;
+
+ /* lookup in function table or call callback in signal handler stack */
+ if (entry->callback)
+ func = entry->callback( pc, entry->context );
+ else
+ func = find_function_info( pc, (HMODULE)entry->base, entry->table, entry->table_size );
+ break;
+ }
+ }
+ RtlLeaveCriticalSection( &dynamic_unwind_section );
+ }
return func;
}
@@ -2528,7 +2577,31 @@ void signal_init_process(void)
*/
BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, DWORD64 addr )
{
- FIXME( "%p %u %lx: stub\n", table, count, addr );
+ struct dynamic_unwind_entry *entry;
+ DWORD size;
+
+ TRACE( "%p %u %lx\n", table, count, addr );
+
+ /* both low-order bits must be unset */
+ if (((ULONG_PTR)table & 0x3) != 0)
+ return FALSE;
+
+ size = table[count - 1].EndAddress;
+ entry = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry) );
+ if (!entry)
+ return FALSE;
+
+ entry->base = addr;
+ entry->size = size;
+ entry->table = table;
+ entry->table_size = count * sizeof(RUNTIME_FUNCTION);
+ entry->callback = NULL; /* unused */
+ entry->context = NULL; /* unused */
+
+ RtlEnterCriticalSection( &dynamic_unwind_section );
+ list_add_tail( &dynamic_unwind_list, &entry->entry );
+ RtlLeaveCriticalSection( &dynamic_unwind_section );
+
return TRUE;
}
@@ -2538,7 +2611,57 @@ BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, DWORD64
*/
BOOLEAN CDECL RtlDeleteFunctionTable( RUNTIME_FUNCTION *table )
{
- FIXME( "%p: stub\n", table );
+ struct dynamic_unwind_entry *entry, *old_entry = NULL;
+
+ TRACE( "%p\n", table );
+
+ RtlEnterCriticalSection( &dynamic_unwind_section );
+ LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry )
+ {
+ if (entry->table == table)
+ {
+ old_entry = entry;
+ list_remove( &entry->entry );
+ break;
+ }
+ }
+ RtlLeaveCriticalSection( &dynamic_unwind_section );
+
+ if (old_entry)
+ RtlFreeHeap( GetProcessHeap(), 0, old_entry );
+
+ return (old_entry != NULL);
+}
+
+
+/**********************************************************************
+ * RtlInstallFunctionTableCallback (NTDLL.@)
+ */
+BOOLEAN CDECL RtlInstallFunctionTableCallback( DWORD64 table, DWORD64 base, DWORD length, PVOID callback, PVOID context, PCWSTR dll )
+{
+ struct dynamic_unwind_entry *entry;
+
+ TRACE( "%lx %lx %d %p %p %s\n", table, base, length, callback, context, wine_dbgstr_w(dll) );
+
+ /* both low-order bits must be set, callback must be provided */
+ if ((table & 0x3) != 0x3 || !callback)
+ return FALSE;
+
+ entry = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry) );
+ if (!entry)
+ return FALSE;
+
+ entry->base = base;
+ entry->size = length;
+ entry->table = (RUNTIME_FUNCTION *)table;
+ entry->table_size = 0; /* unused */
+ entry->callback = callback;
+ entry->context = context;
+
+ RtlEnterCriticalSection( &dynamic_unwind_section );
+ list_add_tail( &dynamic_unwind_list, &entry->entry );
+ RtlLeaveCriticalSection( &dynamic_unwind_section );
+
return TRUE;
}
--
1.7.9.5

View File

@ -0,0 +1,3 @@
Revision: 1
Author: Sebastian Lackner
Title: Add implementation for dynamic unwind tables/callbacks on x86_64.

View File

@ -1,46 +0,0 @@
From dab7a4a879b718afa79f0b1f1f90c5868277d8a8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
Date: Sun, 23 Mar 2014 23:17:51 +0100
Subject: ntdll: Stub RtlInstallFunctionTableCallback
---
dlls/ntdll/ntdll.spec | 1 +
dlls/ntdll/signal_x86_64.c | 10 ++++++++++
2 files changed, 11 insertions(+)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 3c751ea..df79ed0 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -689,6 +689,7 @@
# @ stub RtlInitializeStackTraceDataBase
@ stub RtlInsertElementGenericTable
# @ stub RtlInsertElementGenericTableAvl
+@ cdecl -arch=x86_64 RtlInstallFunctionTableCallback(long long long ptr ptr ptr)
@ stdcall RtlInt64ToUnicodeString(int64 long ptr)
@ stdcall RtlIntegerToChar(long long long ptr)
@ stdcall RtlIntegerToUnicodeString(long long ptr)
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index b28cb99..bd7f2d7 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -2534,6 +2534,16 @@ BOOLEAN CDECL RtlDeleteFunctionTable( RUNTIME_FUNCTION *table )
/**********************************************************************
+ * RtlInstallFunctionTableCallback (NTDLL.@)
+ */
+BOOLEAN CDECL RtlInstallFunctionTableCallback( DWORD64 table, DWORD64 base, DWORD length, PVOID callback, PVOID context, PCWSTR dll )
+{
+ FIXME( "%lx %lx %d %p %p %s: stub\n", table, base, length, callback, context, wine_dbgstr_w(dll) );
+ return TRUE;
+}
+
+
+/**********************************************************************
* RtlLookupFunctionEntry (NTDLL.@)
*/
PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG64 pc, ULONG64 *base, UNWIND_HISTORY_TABLE *table )
--
1.8.3.2

View File

@ -1,3 +0,0 @@
Revision: 1
Author: Michael Müller
Title: Add stub for RtlInstallFunctionTableCallback

View File

@ -57,10 +57,10 @@ index a273502..5fa0cd5 100644
+ { "4cd13e94-7f2d-11e3-b5eb-0090f5c75ad5:1", "Erich E. Hoover", "Support for junction points/reparse points." },
+ { "5fb1f5c8-7f17-11e3-9b62-0090f5c75ad5:1", "Erich E. Hoover", "Implement TransmitFile." },
+ { "3d7c4774-9e7f-11e3-9cfc-0090f5c75ad5:1", "Erich E. Hoover", "Implement missing fonts expected by Silverlight." },
+ { "bbbf7d25-cca0-4630-9a83-0dec5e53ecb8:1", "Sebastian Lackner", "Add implementation for dynamic unwind tables/callbacks on x86_64." },
+ { "0b21d7ac-0387-4493-aa38-fbafe3e749f5:1", "Michael Müller", "Decrease minimum SetTimer interval from 15 to 5 ms." },
+ { "19835498-8d90-4673-867e-2376af4d7c76:1", "Sebastian Lackner", "Allow to set wined3d strictDrawOrdering via environment variable." },
+ { "59bd38b7-bbdc-4cfd-9ccd-1c72c4ed84c0:1", "Sebastian Lackner", "Implement X11DRV_FLUSH_GDI_DISPLAY ExtEscape command." },
+ { "6528a473-8246-49d5-b63c-b47d66b85a74:1", "Michael Müller", "Add stub for RtlInstallFunctionTableCallback" },
+ { "acff3012-0f75-4710-9941-08b5ce4c61f3:1", "Erich E. Hoover", "wined3d: Silence repeated resource_check_usage FIXME." },
+ { "eec5dea8-879d-417b-9f97-364deaae6576:1", "Sebastian Lackner", "Add tests for IVMRMonitorConfig." },
+ { "e46b26df-3c1b-419c-9579-f0d1e1c50bea:1", "Sebastian Lackner", "Workaround for broken implementation of shlwapi url functions." },