Sebastian Lackner : ntdll/tests: Add tests for dynamic unwind table.
Alexandre Julliard
julliard at winehq.org
Tue Apr 8 14:02:51 CDT 2014
Module: wine
Branch: master
Commit: 7821be356d4c3df1e532427d8241396725e974b1
URL: http://source.winehq.org/git/wine.git/?a=commit;h=7821be356d4c3df1e532427d8241396725e974b1
Author: Sebastian Lackner <sebastian at fds-team.de>
Date: Mon Apr 7 01:14:20 2014 +0200
ntdll/tests: Add tests for dynamic unwind table.
---
dlls/ntdll/tests/exception.c | 136 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 136 insertions(+)
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index b4cbaf5..817a19c 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -51,6 +51,13 @@ static NTSTATUS (WINAPI *pNtQueryInformationProcess)(HANDLE, PROCESSINFOCLASS,
static NTSTATUS (WINAPI *pNtSetInformationProcess)(HANDLE, PROCESSINFOCLASS, PVOID, ULONG);
static BOOL (WINAPI *pIsWow64Process)(HANDLE, PBOOL);
+#if defined(__x86_64__)
+static BOOLEAN (CDECL *pRtlAddFunctionTable)(RUNTIME_FUNCTION*, DWORD, DWORD64);
+static BOOLEAN (CDECL *pRtlDeleteFunctionTable)(RUNTIME_FUNCTION*);
+static BOOLEAN (CDECL *pRtlInstallFunctionTableCallback)(DWORD64, DWORD64, DWORD, PGET_RUNTIME_FUNCTION_CALLBACK, PVOID, PCWSTR);
+static PRUNTIME_FUNCTION (WINAPI *pRtlLookupFunctionEntry)(ULONG64, ULONG64*, UNWIND_HISTORY_TABLE*);
+#endif
+
#ifdef __i386__
#ifndef __WINE_WINTRNL_H
@@ -1447,6 +1454,122 @@ static void test_virtual_unwind(void)
call_virtual_unwind( i, &tests[i] );
}
+static RUNTIME_FUNCTION* CALLBACK dynamic_unwind_callback( DWORD64 pc, PVOID context )
+{
+ static const int code_offset = 1024;
+ static RUNTIME_FUNCTION runtime_func;
+ (*(DWORD *)context)++;
+
+ runtime_func.BeginAddress = code_offset + 16;
+ runtime_func.EndAddress = code_offset + 32;
+ 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;
+
+ /* Test RtlAddFunctionTable with 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 );
+
+ /* Lookup function outside of any function table */
+ 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 );
+
+ /* Test with pointer inside of our 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 );
+
+ /* Test RtlDeleteFunctionTable */
+ 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 );
+
+ /* Test RtlInstallFunctionTableCallback with both low bits unset */
+ table = (ULONG_PTR)code_mem;
+ ok( !pRtlInstallFunctionTableCallback( table, (ULONG_PTR)code_mem, code_offset + 32, &dynamic_unwind_callback, (PVOID*)&count, NULL ),
+ "RtlInstallFunctionTableCallback returned success for table = %lx\n", table );
+
+ /* Test RtlInstallFunctionTableCallback with both low bits set */
+ table = (ULONG_PTR)code_mem | 0x3;
+ ok( pRtlInstallFunctionTableCallback( table, (ULONG_PTR)code_mem, code_offset + 32, &dynamic_unwind_callback, (PVOID*)&count, NULL ),
+ "RtlInstallFunctionTableCallback failed for table = %lx\n", table );
+
+ /* Lookup function outside of any function table */
+ count = 0;
+ base = 0xdeadbeef;
+ func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 32, &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 dynamic_unwind_callback\n", count );
+
+ /* Test with pointer inside of our function */
+ count = 0;
+ base = 0xdeadbeef;
+ func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 24, &base, NULL );
+ ok( func != NULL && func->BeginAddress == code_offset + 16 && func->EndAddress == code_offset + 32,
+ "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 dynamic_unwind_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)
@@ -1534,9 +1657,22 @@ START_TEST(exception)
test_dpe_exceptions();
#elif defined(__x86_64__)
+ pRtlAddFunctionTable = (void *)GetProcAddress( hntdll,
+ "RtlAddFunctionTable" );
+ pRtlDeleteFunctionTable = (void *)GetProcAddress( hntdll,
+ "RtlDeleteFunctionTable" );
+ pRtlInstallFunctionTableCallback = (void *)GetProcAddress( hntdll,
+ "RtlInstallFunctionTableCallback" );
+ pRtlLookupFunctionEntry = (void *)GetProcAddress( hntdll,
+ "RtlLookupFunctionEntry" );
test_virtual_unwind();
+ if (pRtlAddFunctionTable && pRtlDeleteFunctionTable && pRtlInstallFunctionTableCallback && pRtlLookupFunctionEntry)
+ test_dynamic_unwind();
+ else
+ skip( "Dynamic unwind functions not found\n" );
+
#endif
VirtualFree(code_mem, 0, MEM_FREE);
More information about the wine-cvs
mailing list