[PATCH 3/3] ntdll: Implement growable unwind tables API.

Nikolay Sivov nsivov at codeweavers.com
Tue Jan 22 23:23:50 CST 2019


Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46479
Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/ntdll/ntdll.spec        |  1 +
 dlls/ntdll/signal_arm.c      | 10 ++++-
 dlls/ntdll/signal_arm64.c    |  9 +++-
 dlls/ntdll/signal_x86_64.c   | 70 +++++++++++++++++++++++++++++--
 dlls/ntdll/tests/exception.c | 80 +++++++++++++++++++++++++++++++++++-
 5 files changed, 163 insertions(+), 7 deletions(-)

diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec
index c2e2fb1c66..09f90980a4 100644
--- a/dlls/ntdll/ntdll.spec
+++ b/dlls/ntdll/ntdll.spec
@@ -542,6 +542,7 @@
 @ stdcall RtlDeleteAce(ptr long)
 @ stdcall RtlDeleteAtomFromAtomTable(ptr long)
 @ stdcall RtlDeleteCriticalSection(ptr)
+@ cdecl -arch=arm,arm64,x86_64 RtlDeleteGrowableFunctionTable(ptr)
 @ stub RtlDeleteElementGenericTable
 @ stub RtlDeleteElementGenericTableAvl
 @ cdecl -arch=arm,arm64,x86_64 RtlDeleteFunctionTable(ptr)
diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c
index 88914cd096..e22480878d 100644
--- a/dlls/ntdll/signal_arm.c
+++ b/dlls/ntdll/signal_arm.c
@@ -1066,7 +1066,7 @@ DWORD WINAPI RtlAddGrowableFunctionTable( void **table, RUNTIME_FUNCTION *functi
 {
     FIXME( "(%p, %p, %d, %d, %ld, %ld) stub!\n", table, functions, count, max_count, base, end );
     if (table) *table = NULL;
-    return S_OK;
+    return STATUS_SUCCESS;
 }
 
 /*************************************************************************
@@ -1077,6 +1077,14 @@ void WINAPI RtlGrowFunctionTable( void *table, DWORD count )
     FIXME( "(%p, %d) stub!\n", table, count );
 }
 
+/*************************************************************************
+ *              RtlDeleteGrowableFunctionTable   (NTDLL.@)
+ */
+void WINAPI RtlDeleteGrowableFunctionTable( void *table )
+{
+    FIXME( "(%p) stub!\n", table );
+}
+
 /**********************************************************************
  *              RtlDeleteFunctionTable   (NTDLL.@)
  */
diff --git a/dlls/ntdll/signal_arm64.c b/dlls/ntdll/signal_arm64.c
index e1958890af..c063be5c85 100644
--- a/dlls/ntdll/signal_arm64.c
+++ b/dlls/ntdll/signal_arm64.c
@@ -986,7 +986,7 @@ DWORD WINAPI RtlAddGrowableFunctionTable( void **table, RUNTIME_FUNCTION *functi
 {
     FIXME( "(%p, %p, %d, %d, %ld, %ld) stub!\n", table, functions, count, max_count, base, end );
     if (table) *table = NULL;
-    return S_OK;
+    return STATUS_SUCCESS;
 }
 
 
@@ -998,6 +998,13 @@ void WINAPI RtlGrowFunctionTable( void *table, DWORD count )
     FIXME( "(%p, %d) stub!\n", table, count );
 }
 
+/*************************************************************************
+ *              RtlDeleteGrowableFunctionTable   (NTDLL.@)
+ */
+void WINAPI RtlDeleteGrowableFunctionTable( void *table )
+{
+    FIXME( "(%p) stub!\n", table );
+}
 
 /**********************************************************************
  *              RtlDeleteFunctionTable   (NTDLL.@)
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index dd820007d3..cbb3dd7617 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -343,6 +343,7 @@ struct dynamic_unwind_entry
     /* lookup table */
     RUNTIME_FUNCTION *table;
     DWORD count;
+    DWORD max_count;
 
     /* user defined callback */
     PGET_RUNTIME_FUNCTION_CALLBACK callback;
@@ -3460,6 +3461,7 @@ BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, DWORD64
     entry->end       = addr + table[count - 1].EndAddress;
     entry->table     = table;
     entry->count     = count;
+    entry->max_count = 0;
     entry->callback  = NULL;
     entry->context   = NULL;
 
@@ -3495,6 +3497,7 @@ BOOLEAN CDECL RtlInstallFunctionTableCallback( DWORD64 table, DWORD64 base, DWOR
     entry->end       = base + length;
     entry->table     = (RUNTIME_FUNCTION *)table;
     entry->count     = 0;
+    entry->max_count = 0;
     entry->callback  = callback;
     entry->context   = context;
 
@@ -3512,9 +3515,29 @@ BOOLEAN CDECL RtlInstallFunctionTableCallback( DWORD64 table, DWORD64 base, DWOR
 DWORD WINAPI RtlAddGrowableFunctionTable( void **table, RUNTIME_FUNCTION *functions, DWORD count, DWORD max_count,
                                           ULONG_PTR base, ULONG_PTR end )
 {
-    FIXME( "(%p, %p, %d, %d, %ld, %ld) semi-stub!\n", table, functions, count, max_count, base, end );
-    if (table) *table = NULL;
-    return RtlAddFunctionTable(functions, count, base);
+    struct dynamic_unwind_entry *entry;
+
+    TRACE( "%p, %p, %u, %u, %lx, %lx\n", table, functions, count, max_count, base, end );
+
+    entry = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry) );
+    if (!entry)
+        return STATUS_NO_MEMORY;
+
+    entry->base      = base;
+    entry->end       = end;
+    entry->table     = functions;
+    entry->count     = count;
+    entry->max_count = max_count;
+    entry->callback  = NULL;
+    entry->context   = NULL;
+
+    RtlEnterCriticalSection( &dynamic_unwind_section );
+    list_add_tail( &dynamic_unwind_list, &entry->entry );
+    RtlLeaveCriticalSection( &dynamic_unwind_section );
+
+    *table = entry;
+
+    return STATUS_SUCCESS;
 }
 
 
@@ -3523,7 +3546,46 @@ DWORD WINAPI RtlAddGrowableFunctionTable( void **table, RUNTIME_FUNCTION *functi
  */
 void WINAPI RtlGrowFunctionTable( void *table, DWORD count )
 {
-    FIXME( "(%p, %d) stub!\n", table, count );
+    struct dynamic_unwind_entry *entry;
+
+    TRACE( "%p, %u\n", table, count );
+
+    RtlEnterCriticalSection( &dynamic_unwind_section );
+    LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry )
+    {
+        if (entry == table)
+        {
+            if (count > entry->count && count <= entry->max_count)
+                entry->count = count;
+            break;
+        }
+    }
+    RtlLeaveCriticalSection( &dynamic_unwind_section );
+}
+
+
+/*************************************************************************
+ *              RtlDeleteGrowableFunctionTable   (NTDLL.@)
+ */
+void WINAPI RtlDeleteGrowableFunctionTable( void *table )
+{
+    struct dynamic_unwind_entry *entry, *to_free = 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)
+        {
+            to_free = entry;
+            list_remove( &entry->entry );
+            break;
+        }
+    }
+    RtlLeaveCriticalSection( &dynamic_unwind_section );
+
+    RtlFreeHeap( GetProcessHeap(), 0, to_free );
 }
 
 
diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c
index 5998f54b04..dee8a9fe47 100644
--- a/dlls/ntdll/tests/exception.c
+++ b/dlls/ntdll/tests/exception.c
@@ -146,6 +146,9 @@ 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*);
+static DWORD     (CDECL *pRtlAddGrowableFunctionTable)(void**, RUNTIME_FUNCTION*, DWORD, DWORD, ULONG_PTR, ULONG_PTR);
+static void      (CDECL *pRtlGrowFunctionTable)(void*, DWORD);
+static void      (CDECL *pRtlDeleteGrowableFunctionTable)(void*);
 static EXCEPTION_DISPOSITION (WINAPI *p__C_specific_handler)(EXCEPTION_RECORD*, ULONG64, CONTEXT*, DISPATCHER_CONTEXT*);
 static VOID      (WINAPI *pRtlCaptureContext)(CONTEXT*);
 static VOID      (CDECL *pRtlRestoreContext)(CONTEXT*, EXCEPTION_RECORD*);
@@ -2037,9 +2040,11 @@ static RUNTIME_FUNCTION* CALLBACK dynamic_unwind_callback( DWORD64 pc, PVOID con
 static void test_dynamic_unwind(void)
 {
     static const int code_offset = 1024;
-    char buf[sizeof(RUNTIME_FUNCTION) + 4];
+    char buf[2 * sizeof(RUNTIME_FUNCTION) + 4];
     RUNTIME_FUNCTION *runtime_func, *func;
     ULONG_PTR table, base;
+    void *growable_table;
+    NTSTATUS status;
     DWORD count;
 
     /* Test RtlAddFunctionTable with aligned RUNTIME_FUNCTION pointer */
@@ -2136,6 +2141,76 @@ static void test_dynamic_unwind(void)
     ok( !pRtlDeleteFunctionTable( (PRUNTIME_FUNCTION)table ),
         "RtlDeleteFunctionTable returned success for nonexistent table = %p\n", (PVOID)table );
 
+    if (!pRtlAddGrowableFunctionTable)
+    {
+        win_skip("Growable function tables are not supported.\n");
+        return;
+    }
+
+    runtime_func = (RUNTIME_FUNCTION *)buf;
+    runtime_func->BeginAddress = code_offset;
+    runtime_func->EndAddress   = code_offset + 16;
+    runtime_func->UnwindData   = 0;
+    runtime_func++;
+    runtime_func->BeginAddress = code_offset + 16;
+    runtime_func->EndAddress   = code_offset + 32;
+    runtime_func->UnwindData   = 0;
+    runtime_func = (RUNTIME_FUNCTION *)buf;
+
+    growable_table = NULL;
+    status = pRtlAddGrowableFunctionTable( &growable_table, runtime_func, 1, 1, (ULONG_PTR)code_mem, (ULONG_PTR)code_mem + 64 );
+    ok(!status, "RtlAddGrowableFunctionTable failed for runtime_func = %p (aligned), %#x.\n", runtime_func, status );
+    ok(growable_table != 0, "Unexpected table value.\n");
+    pRtlDeleteGrowableFunctionTable( growable_table );
+
+    growable_table = NULL;
+    status = pRtlAddGrowableFunctionTable( &growable_table, runtime_func, 2, 2, (ULONG_PTR)code_mem, (ULONG_PTR)code_mem + 64 );
+    ok(!status, "RtlAddGrowableFunctionTable failed for runtime_func = %p (aligned), %#x.\n", runtime_func, status );
+    ok(growable_table != 0, "Unexpected table value.\n");
+    pRtlDeleteGrowableFunctionTable( growable_table );
+
+    growable_table = NULL;
+    status = pRtlAddGrowableFunctionTable( &growable_table, runtime_func, 1, 2, (ULONG_PTR)code_mem, (ULONG_PTR)code_mem + 64 );
+    ok(!status, "RtlAddGrowableFunctionTable failed for runtime_func = %p (aligned), %#x.\n", runtime_func, status );
+    ok(growable_table != 0, "Unexpected table value.\n");
+    pRtlDeleteGrowableFunctionTable( growable_table );
+
+    growable_table = NULL;
+    status = pRtlAddGrowableFunctionTable( &growable_table, runtime_func, 0, 2, (ULONG_PTR)code_mem,
+            (ULONG_PTR)code_mem + code_offset + 64 );
+    ok(!status, "RtlAddGrowableFunctionTable failed for runtime_func = %p (aligned), %#x.\n", runtime_func, status );
+    ok(growable_table != 0, "Unexpected table value.\n");
+
+    /* Current count is 0. */
+    func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 8, &base, NULL );
+    ok( func == NULL,
+        "RtlLookupFunctionEntry didn't return expected function, expected: %p, got: %p\n", runtime_func, func );
+
+    pRtlGrowFunctionTable( growable_table, 1 );
+
+    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 );
+
+    /* Second function is inaccessible yet. */
+    base = 0xdeadbeef;
+    func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 16, &base, NULL );
+    ok( func == NULL,
+        "RtlLookupFunctionEntry didn't return expected function, expected: %p, got: %p\n", runtime_func, func );
+
+    pRtlGrowFunctionTable( growable_table, 2 );
+
+    base = 0xdeadbeef;
+    func = pRtlLookupFunctionEntry( (ULONG_PTR)code_mem + code_offset + 16, &base, NULL );
+    ok( func == runtime_func + 1,
+        "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 );
+
+    pRtlDeleteGrowableFunctionTable( growable_table );
 }
 
 static int termination_handler_called;
@@ -3155,6 +3230,9 @@ START_TEST(exception)
                                                                  "RtlInstallFunctionTableCallback" );
     pRtlLookupFunctionEntry            = (void *)GetProcAddress( hntdll,
                                                                  "RtlLookupFunctionEntry" );
+    pRtlAddGrowableFunctionTable       = (void *)GetProcAddress( hntdll, "RtlAddGrowableFunctionTable" );
+    pRtlGrowFunctionTable              = (void *)GetProcAddress( hntdll, "RtlGrowFunctionTable" );
+    pRtlDeleteGrowableFunctionTable    = (void *)GetProcAddress( hntdll, "RtlDeleteGrowableFunctionTable" );
     p__C_specific_handler              = (void *)GetProcAddress( hntdll,
                                                                  "__C_specific_handler" );
     pRtlCaptureContext                 = (void *)GetProcAddress( hntdll,
-- 
2.20.1




More information about the wine-devel mailing list