Update dynamic unwind patches and add test.

This commit is contained in:
Sebastian Lackner 2014-04-05 01:24:13 +02:00
parent 74bd451363
commit 3de6b17d8a
5 changed files with 211 additions and 16 deletions

View File

@ -1,4 +1,4 @@
From 00e4f5ab76c745a28079c634dd9cf76456b81e22 Mon Sep 17 00:00:00 2001
From 565726f893787072a12329af854e072c5d325906 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.

View File

@ -1,12 +1,13 @@
From 8e29d9d7826cb1e5749909e4fe388af8dcf4a2f3 Mon Sep 17 00:00:00 2001
From efcbb9869c71a40f88ff0c4516f0d65419394104 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(-)
dlls/ntdll/signal_x86_64.c | 128 +++++++++++++++++++++++++++++++++++++++++++-
include/winnt.h | 3 ++
3 files changed, 130 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index 0dd75a2..7a3c3f1 100644
@ -21,7 +22,7 @@ index 0dd75a2..7a3c3f1 100644
@ 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..47bdf54 100644
index 57afe16..c8e1a16 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -56,6 +56,7 @@
@ -50,7 +51,7 @@ index 57afe16..47bdf54 100644
+ RUNTIME_FUNCTION *table;
+ DWORD table_size;
+
+ PRUNTIME_FUNCTION (CDECL *callback)( DWORD pc, PVOID context );
+ PGET_RUNTIME_FUNCTION_CALLBACK callback;
+ PVOID context;
+};
+
@ -101,7 +102,7 @@ index 57afe16..47bdf54 100644
return func;
}
@@ -2528,7 +2577,31 @@ void signal_init_process(void)
@@ -2528,7 +2577,29 @@ void signal_init_process(void)
*/
BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, DWORD64 addr )
{
@ -111,9 +112,7 @@ index 57afe16..47bdf54 100644
+
+ TRACE( "%p %u %lx\n", table, count, addr );
+
+ /* both low-order bits must be unset */
+ if (((ULONG_PTR)table & 0x3) != 0)
+ return FALSE;
+ /* NOTE: Windows doesn't check if table is aligned or a NULL pointer */
+
+ size = table[count - 1].EndAddress;
+ entry = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry) );
@ -134,7 +133,7 @@ index 57afe16..47bdf54 100644
return TRUE;
}
@@ -2538,7 +2611,57 @@ BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, DWORD64
@@ -2538,7 +2609,60 @@ BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, DWORD64
*/
BOOLEAN CDECL RtlDeleteFunctionTable( RUNTIME_FUNCTION *table )
{
@ -165,14 +164,17 @@ index 57afe16..47bdf54 100644
+/**********************************************************************
+ * RtlInstallFunctionTableCallback (NTDLL.@)
+ */
+BOOLEAN CDECL RtlInstallFunctionTableCallback( DWORD64 table, DWORD64 base, DWORD length, PVOID callback, PVOID context, PCWSTR dll )
+BOOLEAN CDECL RtlInstallFunctionTableCallback( DWORD64 table, DWORD64 base, DWORD length,
+ PGET_RUNTIME_FUNCTION_CALLBACK 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)
+ /* NOTE: Windows doesn't check if the provided callback is a NULL pointer */
+
+ /* both low-order bits must be set */
+ if ((table & 0x3) != 0x3)
+ return FALSE;
+
+ entry = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry) );
@ -193,6 +195,22 @@ index 57afe16..47bdf54 100644
return TRUE;
}
diff --git a/include/winnt.h b/include/winnt.h
index 93fd70a..3f33c6b 100644
--- a/include/winnt.h
+++ b/include/winnt.h
@@ -1193,8 +1193,11 @@ typedef struct _KNONVOLATILE_CONTEXT_POINTERS
} DUMMYUNIONNAME2;
} KNONVOLATILE_CONTEXT_POINTERS, *PKNONVOLATILE_CONTEXT_POINTERS;
+typedef PRUNTIME_FUNCTION (CALLBACK *PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64,PVOID);
+
BOOLEAN CDECL RtlAddFunctionTable(RUNTIME_FUNCTION*,DWORD,DWORD64);
BOOLEAN CDECL RtlDeleteFunctionTable(RUNTIME_FUNCTION*);
+BOOLEAN CDECL RtlInstallFunctionTableCallback(DWORD64,DWORD64,DWORD,PGET_RUNTIME_FUNCTION_CALLBACK,PVOID,PCWSTR);
PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry(DWORD64,DWORD64*,UNWIND_HISTORY_TABLE*);
PVOID WINAPI RtlVirtualUnwind(ULONG,ULONG64,ULONG64,RUNTIME_FUNCTION*,CONTEXT*,PVOID*,ULONG64*,KNONVOLATILE_CONTEXT_POINTERS*);
--
1.7.9.5

View File

@ -0,0 +1,177 @@
From fe1571d281c60aa9a1db503c8d143ac5029982c2 Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Sat, 5 Apr 2014 01:04:25 +0200
Subject: ntdll/tests: Add tests for dynamic unwind table.
---
dlls/ntdll/tests/exception.c | 133 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 133 insertions(+)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index b4cbaf5..ac70802 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -49,6 +49,10 @@ static NTSTATUS (WINAPI *pNtReadVirtualMemory)(HANDLE, const void*, void*, SIZE
static NTSTATUS (WINAPI *pNtTerminateProcess)(HANDLE handle, LONG exit_code);
static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG, PULONG);
static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
+static BOOLEAN (WINAPI *pRtlAddFunctionTable)(RUNTIME_FUNCTION*, DWORD, DWORD64);
+static BOOLEAN (WINAPI *pRtlDeleteFunctionTable)(RUNTIME_FUNCTION*);
+static BOOLEAN (WINAPI *pRtlInstallFunctionTableCallback)(DWORD64, DWORD64, DWORD, PGET_RUNTIME_FUNCTION_CALLBACK, PVOID, PCWSTR);
+static PRUNTIME_FUNCTION (WINAPI *pRtlLookupFunctionEntry)(ULONG64, ULONG64*, UNWIND_HISTORY_TABLE*);
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
#ifdef __i386__
@@ -1447,6 +1451,122 @@ static void test_virtual_unwind(void)
call_virtual_unwind( i, &tests[i] );
}
+static RUNTIME_FUNCTION* CALLBACK function_table_callback( DWORD64 pc, PVOID context )
+{
+ static const int code_offset = 1024;
+ static RUNTIME_FUNCTION runtime_func;
+ (*(DWORD *)context)++;
+
+ runtime_func.BeginAddress = code_offset;
+ runtime_func.EndAddress = code_offset + 16;
+ runtime_func.UnwindData = 0;
+ return &runtime_func;
+}
+
+static void test_dynamic_unwind(void)
+{
+ static const int code_offset = 1024;
+ char buf[sizeof(RUNTIME_FUNCTION) + 4];
+ RUNTIME_FUNCTION *runtime_func, *func;
+ ULONG_PTR table, base;
+ DWORD count;
+
+ /* Aligned RUNTIME_FUNCTION pointer */
+ runtime_func = (RUNTIME_FUNCTION *)buf;
+ runtime_func->BeginAddress = code_offset;
+ runtime_func->EndAddress = code_offset + 16;
+ runtime_func->UnwindData = 0;
+ ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ),
+ "RtlAddFunctionTable failed for runtime_func = %p (aligned)\n", runtime_func );
+
+ /* Pointer outside of the area */
+ base = 0xdeadbeef;
+ func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 16, &base, NULL );
+ ok( func == NULL,
+ "RtlLookupFunctionEntry returned unexpected function, expected: NULL, got: %p\n", func );
+ ok( base == 0xdeadbeef,
+ "RtlLookupFunctionEntry modified base address, expected: 0xdeadbeef, got: %lx\n", base );
+
+ /* Pointer inside of a function */
+ base = 0xdeadbeef;
+ func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 8, &base, NULL );
+ ok( func == runtime_func,
+ "RtlLookupFunctionEntry didn't return expected function, expected: %p, got: %p\n", runtime_func, func );
+ ok( base == (ULONG_PTR)code_mem,
+ "RtlLookupFunctionEntry returned invalid base, expected: %lx, got: %lx\n", (ULONG_PTR)code_mem, base );
+
+ /* Ensure that deleting is also successful */
+ ok( pRtlDeleteFunctionTable( runtime_func ),
+ "RtlDeleteFunctionTable failed for runtime_func = %p (aligned)\n", runtime_func );
+ ok( !pRtlDeleteFunctionTable( runtime_func ),
+ "RtlDeleteFunctionTable returned success for nonexistent table runtime_func = %p\n", runtime_func );
+
+ /* Unaligned RUNTIME_FUNCTION pointer */
+ runtime_func = (RUNTIME_FUNCTION *)((ULONG_PTR)buf | 0x3);
+ runtime_func->BeginAddress = code_offset;
+ runtime_func->EndAddress = code_offset + 16;
+ runtime_func->UnwindData = 0;
+ ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ),
+ "RtlAddFunctionTable failed for runtime_func = %p (unaligned)\n", runtime_func );
+ ok( pRtlDeleteFunctionTable( runtime_func ),
+ "RtlDeleteFunctionTable failed for runtime_func = %p (unaligned)\n", runtime_func );
+
+ /* Attempt to insert the same entry twice */
+ runtime_func = (RUNTIME_FUNCTION *)buf;
+ runtime_func->BeginAddress = code_offset;
+ runtime_func->EndAddress = code_offset + 16;
+ runtime_func->UnwindData = 0;
+ ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ),
+ "RtlAddFunctionTable failed for runtime_func = %p (first attempt)\n", runtime_func );
+ ok( pRtlAddFunctionTable( runtime_func, 1, (ULONG_PTR)code_mem ),
+ "RtlAddFunctionTable failed for runtime_func = %p (second attempt)\n", runtime_func );
+ ok( pRtlDeleteFunctionTable( runtime_func ),
+ "RtlDeleteFunctionTable failed for runtime_func = %p (first attempt)\n", runtime_func );
+ ok( pRtlDeleteFunctionTable( runtime_func ),
+ "RtlDeleteFunctionTable failed for runtime_func = %p (second attempt)\n", runtime_func );
+ ok( !pRtlDeleteFunctionTable( runtime_func ),
+ "RtlDeleteFunctionTable returned success for nonexistent table runtime_func = %p\n", runtime_func );
+
+ /* Table without both low bits set */
+ table = (ULONG_PTR)code_mem;
+ ok( !pRtlInstallFunctionTableCallback( table, (ULONG_PTR)code_mem, code_offset + 16, &function_table_callback, (PVOID*)&count, NULL ),
+ "RtlInstallFunctionTableCallback returned success for table = %lx\n", table );
+
+ /* Table with both low bits set */
+ table = (ULONG_PTR)code_mem | 0x3;
+ ok( pRtlInstallFunctionTableCallback( table, (ULONG_PTR)code_mem, code_offset + 16, &function_table_callback, (PVOID*)&count, NULL ),
+ "RtlInstallFunctionTableCallback failed for table = %lx\n", table );
+
+ /* Pointer outside of the area */
+ count = 0;
+ base = 0xdeadbeef;
+ func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 16, &base, NULL );
+ ok( func == NULL,
+ "RtlLookupFunctionEntry returned unexpected function, expected: NULL, got: %p\n", func );
+ ok( base == 0xdeadbeef,
+ "RtlLookupFunctionEntry modified base address, expected: 0xdeadbeef, got: %lx\n", base );
+ ok( !count,
+ "RtlLookupFunctionEntry issued %d unexpected calls to function_table_callback\n", count );
+
+ /* Pointer inside of a function */
+ count = 0;
+ base = 0xdeadbeef;
+ func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 8, &base, NULL );
+ ok( func != NULL && func->BeginAddress == code_offset && func->EndAddress == code_offset + 16,
+ "RtlLookupFunctionEntry didn't return expected function, got: %p\n", func );
+ ok( base == (ULONG_PTR)code_mem,
+ "RtlLookupFunctionEntry returned invalid base, expected: %lx, got: %lx\n", (ULONG_PTR)code_mem, base );
+ ok( count == 1,
+ "RtlLookupFunctionEntry issued %d calls to function_table_callback, expected: 1\n", count );
+
+ /* Clean up again */
+ ok( pRtlDeleteFunctionTable( (PRUNTIME_FUNCTION)table ),
+ "RtlDeleteFunctionTable failed for table = %p\n", (PVOID)table );
+ ok( !pRtlDeleteFunctionTable( (PRUNTIME_FUNCTION)table ),
+ "RtlDeleteFunctionTable returned success for nonexistent table = %p\n", (PVOID)table );
+
+}
+
#endif /* __x86_64__ */
START_TEST(exception)
@@ -1473,6 +1593,14 @@ START_TEST(exception)
"NtQueryInformationProcess" );
pNtSetInformationProcess = (void*)GetProcAddress( hntdll,
"NtSetInformationProcess" );
+ pRtlAddFunctionTable = (void *)GetProcAddress( hntdll,
+ "RtlAddFunctionTable" );
+ pRtlDeleteFunctionTable = (void *)GetProcAddress( hntdll,
+ "RtlDeleteFunctionTable" );
+ pRtlInstallFunctionTableCallback = (void *)GetProcAddress( hntdll,
+ "RtlInstallFunctionTableCallback" );
+ pRtlLookupFunctionEntry = (void *)GetProcAddress( hntdll,
+ "RtlLookupFunctionEntry" );
pIsWow64Process = (void *)GetProcAddress(GetModuleHandleA("kernel32.dll"), "IsWow64Process");
#ifdef __i386__
@@ -1537,6 +1665,11 @@ START_TEST(exception)
test_virtual_unwind();
+ if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)
+ test_dynamic_unwind();
+ else
+ skip( "Rtl{Add,Delete}FunctionTable or RtlInstallFunctionTableCallback or RtlLookupFunctionEntry not found\n" );
+
#endif
VirtualFree(code_mem, 0, MEM_FREE);
--
1.7.9.5

View File

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

View File

@ -57,7 +57,7 @@ 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." },
+ { "bbbf7d25-cca0-4630-9a83-0dec5e53ecb8:2", "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." },