ntdll: Implement growable unwind tables API.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=46479 Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
0cd5a68ca4
commit
067f6d7463
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue