[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