From 3de6b17d8a28a65b0d1784cadd5d4634c4bb20b8 Mon Sep 17 00:00:00 2001 From: Sebastian Lackner Date: Sat, 5 Apr 2014 01:24:13 +0200 Subject: [PATCH] Update dynamic unwind patches and add test. --- ...-exception-function-lookup-on-x86_64.patch | 2 +- ...ement-dynamic-unwind-table-functions.patch | 44 +++-- ...s-Add-tests-for-dynamic-unwind-table.patch | 177 ++++++++++++++++++ .../bbbf7d25-cca0-4630-9a83-0dec5e53ecb8.def | 2 +- patches/patch-list.patch | 2 +- 5 files changed, 211 insertions(+), 16 deletions(-) create mode 100644 patches/11-Dynamic_Unwind/0003-ntdll-tests-Add-tests-for-dynamic-unwind-table.patch diff --git a/patches/11-Dynamic_Unwind/0001-ntdll-Unify-exception-function-lookup-on-x86_64.patch b/patches/11-Dynamic_Unwind/0001-ntdll-Unify-exception-function-lookup-on-x86_64.patch index 9384292c..930c3dd5 100644 --- a/patches/11-Dynamic_Unwind/0001-ntdll-Unify-exception-function-lookup-on-x86_64.patch +++ b/patches/11-Dynamic_Unwind/0001-ntdll-Unify-exception-function-lookup-on-x86_64.patch @@ -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 Date: Fri, 4 Apr 2014 10:11:56 +0200 Subject: ntdll: Unify exception function lookup on x86_64. diff --git a/patches/11-Dynamic_Unwind/0002-ntdll-Implement-dynamic-unwind-table-functions.patch b/patches/11-Dynamic_Unwind/0002-ntdll-Implement-dynamic-unwind-table-functions.patch index 2a92880f..35364c31 100644 --- a/patches/11-Dynamic_Unwind/0002-ntdll-Implement-dynamic-unwind-table-functions.patch +++ b/patches/11-Dynamic_Unwind/0002-ntdll-Implement-dynamic-unwind-table-functions.patch @@ -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 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 diff --git a/patches/11-Dynamic_Unwind/0003-ntdll-tests-Add-tests-for-dynamic-unwind-table.patch b/patches/11-Dynamic_Unwind/0003-ntdll-tests-Add-tests-for-dynamic-unwind-table.patch new file mode 100644 index 00000000..d35d2caa --- /dev/null +++ b/patches/11-Dynamic_Unwind/0003-ntdll-tests-Add-tests-for-dynamic-unwind-table.patch @@ -0,0 +1,177 @@ +From fe1571d281c60aa9a1db503c8d143ac5029982c2 Mon Sep 17 00:00:00 2001 +From: Sebastian Lackner +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 + diff --git a/patches/11-Dynamic_Unwind/bbbf7d25-cca0-4630-9a83-0dec5e53ecb8.def b/patches/11-Dynamic_Unwind/bbbf7d25-cca0-4630-9a83-0dec5e53ecb8.def index e6844033..80102bf0 100644 --- a/patches/11-Dynamic_Unwind/bbbf7d25-cca0-4630-9a83-0dec5e53ecb8.def +++ b/patches/11-Dynamic_Unwind/bbbf7d25-cca0-4630-9a83-0dec5e53ecb8.def @@ -1,3 +1,3 @@ -Revision: 1 +Revision: 2 Author: Sebastian Lackner Title: Add implementation for dynamic unwind tables/callbacks on x86_64. diff --git a/patches/patch-list.patch b/patches/patch-list.patch index 3e790baa..0d1ad068 100644 --- a/patches/patch-list.patch +++ b/patches/patch-list.patch @@ -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." },