Commit 067f6d74 authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

ntdll: Implement growable unwind tables API.

parent 0cd5a68c
......@@ -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)
......
......@@ -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.@)
*/
......
......@@ -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.@)
......
......@@ -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 );
}
......
......@@ -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,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment