ntdll: Share dynamic exception table functions across platforms.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
44a6043388
commit
14e34bedbf
|
@ -6,7 +6,7 @@
|
|||
@ cdecl -arch=arm,arm64,x86_64 RtlDeleteFunctionTable(ptr) ntdll.RtlDeleteFunctionTable
|
||||
@ stdcall RtlFillMemory(ptr long long) ntdll.RtlFillMemory
|
||||
@ cdecl -arch=arm,arm64,x86_64 RtlInstallFunctionTableCallback(long long long ptr ptr wstr) ntdll.RtlInstallFunctionTableCallback
|
||||
@ stdcall -arch=arm,x86_64 RtlLookupFunctionEntry(long ptr ptr) ntdll.RtlLookupFunctionEntry
|
||||
@ stdcall -arch=arm,arm64,x86_64 RtlLookupFunctionEntry(long ptr ptr) ntdll.RtlLookupFunctionEntry
|
||||
@ stdcall RtlPcToFileHeader(ptr ptr) ntdll.RtlPcToFileHeader
|
||||
@ stdcall -norelay RtlRaiseException(ptr) ntdll.RtlRaiseException
|
||||
@ stdcall -arch=x86_64 RtlRestoreContext(ptr ptr) ntdll.RtlRestoreContext
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#include <signal.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#define NONAMELESSUNION
|
||||
#define NONAMELESSSTRUCT
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
#include "windef.h"
|
||||
|
@ -327,6 +329,344 @@ LONG WINAPI call_unhandled_exception_filter( PEXCEPTION_POINTERS eptr )
|
|||
}
|
||||
|
||||
|
||||
#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
|
||||
|
||||
struct dynamic_unwind_entry
|
||||
{
|
||||
struct list entry;
|
||||
ULONG_PTR base;
|
||||
ULONG_PTR end;
|
||||
RUNTIME_FUNCTION *table;
|
||||
DWORD count;
|
||||
DWORD max_count;
|
||||
PGET_RUNTIME_FUNCTION_CALLBACK callback;
|
||||
PVOID context;
|
||||
};
|
||||
|
||||
static struct list dynamic_unwind_list = LIST_INIT(dynamic_unwind_list);
|
||||
|
||||
static RTL_CRITICAL_SECTION dynamic_unwind_section;
|
||||
static RTL_CRITICAL_SECTION_DEBUG dynamic_unwind_debug =
|
||||
{
|
||||
0, 0, &dynamic_unwind_section,
|
||||
{ &dynamic_unwind_debug.ProcessLocksList, &dynamic_unwind_debug.ProcessLocksList },
|
||||
0, 0, { (DWORD_PTR)(__FILE__ ": dynamic_unwind_section") }
|
||||
};
|
||||
static RTL_CRITICAL_SECTION dynamic_unwind_section = { &dynamic_unwind_debug, -1, 0, 0, 0, 0 };
|
||||
|
||||
static ULONG_PTR get_runtime_function_end( RUNTIME_FUNCTION *func, ULONG_PTR addr )
|
||||
{
|
||||
#ifdef __x86_64__
|
||||
return func->EndAddress;
|
||||
#elif defined(__arm__)
|
||||
if (func->u.s.Flag) return func->BeginAddress + func->u.s.FunctionLength * 2;
|
||||
else
|
||||
{
|
||||
struct unwind_info
|
||||
{
|
||||
DWORD function_length : 18;
|
||||
DWORD version : 2;
|
||||
DWORD x : 1;
|
||||
DWORD e : 1;
|
||||
DWORD f : 1;
|
||||
DWORD count : 5;
|
||||
DWORD words : 4;
|
||||
} *info = (struct unwind_info *)(addr + func->u.UnwindData);
|
||||
return func->BeginAddress + info->function_length * 2;
|
||||
}
|
||||
#else /* __aarch64__ */
|
||||
if (func->u.s.Flag) return func->BeginAddress + func->u.s.FunctionLength * 4;
|
||||
else
|
||||
{
|
||||
struct unwind_info
|
||||
{
|
||||
DWORD function_length : 18;
|
||||
DWORD version : 2;
|
||||
DWORD x : 1;
|
||||
DWORD e : 1;
|
||||
DWORD epilog : 5;
|
||||
DWORD codes : 5;
|
||||
} *info = (struct unwind_info *)(addr + func->u.UnwindData);
|
||||
return func->BeginAddress + info->function_length * 4;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* RtlAddFunctionTable (NTDLL.@)
|
||||
*/
|
||||
BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, ULONG_PTR addr )
|
||||
{
|
||||
struct dynamic_unwind_entry *entry;
|
||||
|
||||
TRACE( "%p %u %lx\n", table, count, addr );
|
||||
|
||||
/* NOTE: Windows doesn't check if table is aligned or a NULL pointer */
|
||||
|
||||
entry = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry) );
|
||||
if (!entry)
|
||||
return FALSE;
|
||||
|
||||
entry->base = addr;
|
||||
entry->end = addr + (count ? get_runtime_function_end( &table[count - 1], addr ) : 0);
|
||||
entry->table = table;
|
||||
entry->count = count;
|
||||
entry->max_count = 0;
|
||||
entry->callback = NULL;
|
||||
entry->context = NULL;
|
||||
|
||||
RtlEnterCriticalSection( &dynamic_unwind_section );
|
||||
list_add_tail( &dynamic_unwind_list, &entry->entry );
|
||||
RtlLeaveCriticalSection( &dynamic_unwind_section );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* RtlInstallFunctionTableCallback (NTDLL.@)
|
||||
*/
|
||||
BOOLEAN CDECL RtlInstallFunctionTableCallback( ULONG_PTR table, ULONG_PTR 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) );
|
||||
|
||||
/* 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) );
|
||||
if (!entry)
|
||||
return FALSE;
|
||||
|
||||
entry->base = base;
|
||||
entry->end = base + length;
|
||||
entry->table = (RUNTIME_FUNCTION *)table;
|
||||
entry->count = 0;
|
||||
entry->max_count = 0;
|
||||
entry->callback = callback;
|
||||
entry->context = context;
|
||||
|
||||
RtlEnterCriticalSection( &dynamic_unwind_section );
|
||||
list_add_tail( &dynamic_unwind_list, &entry->entry );
|
||||
RtlLeaveCriticalSection( &dynamic_unwind_section );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* RtlAddGrowableFunctionTable (NTDLL.@)
|
||||
*/
|
||||
DWORD WINAPI RtlAddGrowableFunctionTable( void **table, RUNTIME_FUNCTION *functions, DWORD count,
|
||||
DWORD max_count, ULONG_PTR base, ULONG_PTR end )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* RtlGrowFunctionTable (NTDLL.@)
|
||||
*/
|
||||
void WINAPI RtlGrowFunctionTable( void *table, DWORD 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 );
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* RtlDeleteFunctionTable (NTDLL.@)
|
||||
*/
|
||||
BOOLEAN CDECL RtlDeleteFunctionTable( RUNTIME_FUNCTION *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 == table)
|
||||
{
|
||||
to_free = entry;
|
||||
list_remove( &entry->entry );
|
||||
break;
|
||||
}
|
||||
}
|
||||
RtlLeaveCriticalSection( &dynamic_unwind_section );
|
||||
|
||||
if (!to_free) return FALSE;
|
||||
|
||||
RtlFreeHeap( GetProcessHeap(), 0, to_free );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* helper for lookup_function_info() */
|
||||
static RUNTIME_FUNCTION *find_function_info( ULONG_PTR pc, ULONG_PTR base,
|
||||
RUNTIME_FUNCTION *func, ULONG size )
|
||||
{
|
||||
int min = 0;
|
||||
int max = size - 1;
|
||||
|
||||
while (min <= max)
|
||||
{
|
||||
#ifdef __x86_64__
|
||||
int pos = (min + max) / 2;
|
||||
if (pc < base + func[pos].BeginAddress) max = pos - 1;
|
||||
else if (pc >= base + func[pos].EndAddress) min = pos + 1;
|
||||
else
|
||||
{
|
||||
func += pos;
|
||||
while (func->UnwindData & 1) /* follow chained entry */
|
||||
func = (RUNTIME_FUNCTION *)(base + (func->UnwindData & ~1));
|
||||
return func;
|
||||
}
|
||||
#elif defined(__arm__)
|
||||
int pos = (min + max) / 2;
|
||||
if (pc < base + (func[pos].BeginAddress & ~1)) max = pos - 1;
|
||||
else if (pc >= base + get_runtime_function_end( &func[pos], base )) min = pos + 1;
|
||||
else return func + pos;
|
||||
#else /* __aarch64__ */
|
||||
int pos = (min + max) / 2;
|
||||
if (pc < base + func[pos].BeginAddress) max = pos - 1;
|
||||
else if (pc >= base + get_runtime_function_end( &func[pos], base )) min = pos + 1;
|
||||
else return func + pos;
|
||||
#endif
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* lookup_function_info
|
||||
*/
|
||||
RUNTIME_FUNCTION *lookup_function_info( ULONG_PTR pc, ULONG_PTR *base, LDR_MODULE **module )
|
||||
{
|
||||
RUNTIME_FUNCTION *func = NULL;
|
||||
struct dynamic_unwind_entry *entry;
|
||||
ULONG size;
|
||||
|
||||
/* PE module or wine module */
|
||||
if (!LdrFindEntryForAddress( (void *)pc, module ))
|
||||
{
|
||||
*base = (ULONG_PTR)(*module)->BaseAddress;
|
||||
if ((func = RtlImageDirectoryEntryToData( (*module)->BaseAddress, TRUE,
|
||||
IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
|
||||
{
|
||||
/* lookup in function table */
|
||||
func = find_function_info( pc, (ULONG_PTR)(*module)->BaseAddress, func, size/sizeof(*func) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*module = NULL;
|
||||
|
||||
RtlEnterCriticalSection( &dynamic_unwind_section );
|
||||
LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry )
|
||||
{
|
||||
if (pc >= entry->base && pc < entry->end)
|
||||
{
|
||||
*base = entry->base;
|
||||
/* use callback or lookup in function table */
|
||||
if (entry->callback)
|
||||
func = entry->callback( pc, entry->context );
|
||||
else
|
||||
func = find_function_info( pc, entry->base, entry->table, entry->count );
|
||||
break;
|
||||
}
|
||||
}
|
||||
RtlLeaveCriticalSection( &dynamic_unwind_section );
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* RtlLookupFunctionEntry (NTDLL.@)
|
||||
*/
|
||||
PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG_PTR pc, ULONG_PTR *base,
|
||||
UNWIND_HISTORY_TABLE *table )
|
||||
{
|
||||
LDR_MODULE *module;
|
||||
RUNTIME_FUNCTION *func;
|
||||
|
||||
/* FIXME: should use the history table to make things faster */
|
||||
|
||||
if (!(func = lookup_function_info( pc, base, &module )))
|
||||
{
|
||||
*base = 0;
|
||||
WARN( "no exception table found for %lx\n", pc );
|
||||
}
|
||||
return func;
|
||||
}
|
||||
|
||||
#endif /* __x86_64__ || __arm__ || __aarch64__ */
|
||||
|
||||
/*************************************************************
|
||||
* __wine_spec_unimplemented_stub
|
||||
*
|
||||
|
|
|
@ -805,7 +805,7 @@
|
|||
@ stdcall RtlLookupAtomInAtomTable(ptr wstr ptr)
|
||||
@ stub RtlLookupElementGenericTable
|
||||
# @ stub RtlLookupElementGenericTableAvl
|
||||
@ stdcall -arch=arm,x86_64 RtlLookupFunctionEntry(long ptr ptr)
|
||||
@ stdcall -arch=arm,arm64,x86_64 RtlLookupFunctionEntry(long ptr ptr)
|
||||
@ stdcall RtlMakeSelfRelativeSD(ptr ptr ptr)
|
||||
@ stdcall RtlMapGenericMask(ptr ptr)
|
||||
# @ stub RtlMapSecurityErrorToNtStatus
|
||||
|
|
|
@ -60,6 +60,10 @@ extern NTSTATUS set_thread_context( HANDLE handle, const context_t *context, BOO
|
|||
extern NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int flags, BOOL *self ) DECLSPEC_HIDDEN;
|
||||
extern LONG WINAPI call_unhandled_exception_filter( PEXCEPTION_POINTERS eptr ) DECLSPEC_HIDDEN;
|
||||
|
||||
#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
|
||||
extern RUNTIME_FUNCTION *lookup_function_info( ULONG_PTR pc, ULONG_PTR *base, LDR_MODULE **module ) DECLSPEC_HIDDEN;
|
||||
#endif
|
||||
|
||||
/* debug helpers */
|
||||
extern LPCSTR debugstr_us( const UNICODE_STRING *str ) DECLSPEC_HIDDEN;
|
||||
extern LPCSTR debugstr_ObjectAttributes(const OBJECT_ATTRIBUTES *oa) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -128,15 +128,6 @@ typedef int (*wine_signal_handler)(unsigned int sig);
|
|||
static wine_signal_handler handlers[256];
|
||||
|
||||
|
||||
struct UNWIND_INFO
|
||||
{
|
||||
WORD function_length;
|
||||
WORD unknown1 : 7;
|
||||
WORD count : 5;
|
||||
WORD unknown2 : 4;
|
||||
};
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_trap_code
|
||||
*
|
||||
|
@ -1064,118 +1055,6 @@ void signal_init_process(void)
|
|||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* RtlAddFunctionTable (NTDLL.@)
|
||||
*/
|
||||
BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, DWORD addr )
|
||||
{
|
||||
FIXME( "%p %u %x: stub\n", table, count, addr );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* RtlInstallFunctionTableCallback (NTDLL.@)
|
||||
*/
|
||||
BOOLEAN CDECL RtlInstallFunctionTableCallback( DWORD table, DWORD base, DWORD length,
|
||||
PGET_RUNTIME_FUNCTION_CALLBACK callback, PVOID context, PCWSTR dll )
|
||||
{
|
||||
FIXME( "%x %x %d %p %p %s: stub\n", table, base, length, callback, context, wine_dbgstr_w(dll) );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* RtlAddGrowableFunctionTable (NTDLL.@)
|
||||
*/
|
||||
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) stub!\n", table, functions, count, max_count, base, end );
|
||||
if (table) *table = NULL;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* RtlGrowFunctionTable (NTDLL.@)
|
||||
*/
|
||||
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.@)
|
||||
*/
|
||||
BOOLEAN CDECL RtlDeleteFunctionTable( RUNTIME_FUNCTION *table )
|
||||
{
|
||||
FIXME( "%p: stub\n", table );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* find_function_info
|
||||
*/
|
||||
static RUNTIME_FUNCTION *find_function_info( ULONG_PTR pc, HMODULE module,
|
||||
RUNTIME_FUNCTION *func, ULONG size )
|
||||
{
|
||||
int min = 0;
|
||||
int max = size/sizeof(*func) - 1;
|
||||
|
||||
while (min <= max)
|
||||
{
|
||||
int pos = (min + max) / 2;
|
||||
DWORD begin = (func[pos].BeginAddress & ~1), end;
|
||||
if (func[pos].u.s.Flag)
|
||||
end = begin + func[pos].u.s.FunctionLength * 2;
|
||||
else
|
||||
{
|
||||
struct UNWIND_INFO *info;
|
||||
info = (struct UNWIND_INFO *)((char *)module + func[pos].u.UnwindData);
|
||||
end = begin + info->function_length * 2;
|
||||
}
|
||||
|
||||
if ((char *)pc < (char *)module + begin) max = pos - 1;
|
||||
else if ((char *)pc >= (char *)module + end) min = pos + 1;
|
||||
else return func + pos;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* RtlLookupFunctionEntry (NTDLL.@)
|
||||
*/
|
||||
PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG_PTR pc, DWORD *base,
|
||||
UNWIND_HISTORY_TABLE *table )
|
||||
{
|
||||
LDR_MODULE *module;
|
||||
RUNTIME_FUNCTION *func;
|
||||
ULONG size;
|
||||
|
||||
/* FIXME: should use the history table to make things faster */
|
||||
|
||||
if (LdrFindEntryForAddress( (void *)pc, &module ))
|
||||
{
|
||||
WARN( "module not found for %lx\n", pc );
|
||||
return NULL;
|
||||
}
|
||||
if (!(func = RtlImageDirectoryEntryToData( module->BaseAddress, TRUE,
|
||||
IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
|
||||
{
|
||||
WARN( "no exception table found in module %p pc %lx\n", module->BaseAddress, pc );
|
||||
return NULL;
|
||||
}
|
||||
func = find_function_info( pc, module->BaseAddress, func, size );
|
||||
if (func) *base = (DWORD)module->BaseAddress;
|
||||
return func;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* RtlUnwind (NTDLL.@)
|
||||
*/
|
||||
|
|
|
@ -971,63 +971,6 @@ void signal_init_process(void)
|
|||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* RtlAddFunctionTable (NTDLL.@)
|
||||
*/
|
||||
BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, ULONG_PTR addr )
|
||||
{
|
||||
FIXME( "%p %u %lx: stub\n", table, count, addr );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* RtlInstallFunctionTableCallback (NTDLL.@)
|
||||
*/
|
||||
BOOLEAN CDECL RtlInstallFunctionTableCallback( ULONG_PTR table, ULONG_PTR base, DWORD length,
|
||||
PGET_RUNTIME_FUNCTION_CALLBACK callback, PVOID context, PCWSTR dll )
|
||||
{
|
||||
FIXME( "%lx %lx %d %p %p %s: stub\n", table, base, length, callback, context, wine_dbgstr_w(dll) );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* RtlAddGrowableFunctionTable (NTDLL.@)
|
||||
*/
|
||||
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) stub!\n", table, functions, count, max_count, base, end );
|
||||
if (table) *table = NULL;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* RtlGrowFunctionTable (NTDLL.@)
|
||||
*/
|
||||
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.@)
|
||||
*/
|
||||
BOOLEAN CDECL RtlDeleteFunctionTable( RUNTIME_FUNCTION *table )
|
||||
{
|
||||
FIXME( "%p: stub\n", table );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* RtlUnwind (NTDLL.@)
|
||||
*/
|
||||
|
|
|
@ -305,39 +305,6 @@ static inline struct amd64_thread_data *amd64_thread_data(void)
|
|||
return (struct amd64_thread_data *)NtCurrentTeb()->SystemReserved2;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Dynamic unwind table
|
||||
*/
|
||||
|
||||
struct dynamic_unwind_entry
|
||||
{
|
||||
struct list entry;
|
||||
|
||||
/* memory region which matches this entry */
|
||||
DWORD64 base;
|
||||
DWORD64 end;
|
||||
|
||||
/* lookup table */
|
||||
RUNTIME_FUNCTION *table;
|
||||
DWORD count;
|
||||
DWORD max_count;
|
||||
|
||||
/* user defined callback */
|
||||
PGET_RUNTIME_FUNCTION_CALLBACK callback;
|
||||
PVOID context;
|
||||
};
|
||||
|
||||
static struct list dynamic_unwind_list = LIST_INIT(dynamic_unwind_list);
|
||||
|
||||
static RTL_CRITICAL_SECTION dynamic_unwind_section;
|
||||
static RTL_CRITICAL_SECTION_DEBUG dynamic_unwind_debug =
|
||||
{
|
||||
0, 0, &dynamic_unwind_section,
|
||||
{ &dynamic_unwind_debug.ProcessLocksList, &dynamic_unwind_debug.ProcessLocksList },
|
||||
0, 0, { (DWORD_PTR)(__FILE__ ": dynamic_unwind_section") }
|
||||
};
|
||||
static RTL_CRITICAL_SECTION dynamic_unwind_section = { &dynamic_unwind_debug, -1, 0, 0, 0, 0 };
|
||||
|
||||
/***********************************************************************
|
||||
* Definitions for Win32 unwind tables
|
||||
*/
|
||||
|
@ -2501,76 +2468,6 @@ static inline CONTEXT *get_exception_context( EXCEPTION_RECORD *rec )
|
|||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* find_function_info
|
||||
*/
|
||||
static RUNTIME_FUNCTION *find_function_info( ULONG64 pc, HMODULE module,
|
||||
RUNTIME_FUNCTION *func, ULONG size )
|
||||
{
|
||||
int min = 0;
|
||||
int max = size - 1;
|
||||
|
||||
while (min <= max)
|
||||
{
|
||||
int pos = (min + max) / 2;
|
||||
if ((char *)pc < (char *)module + func[pos].BeginAddress) max = pos - 1;
|
||||
else if ((char *)pc >= (char *)module + func[pos].EndAddress) min = pos + 1;
|
||||
else
|
||||
{
|
||||
func += pos;
|
||||
while (func->UnwindData & 1) /* follow chained entry */
|
||||
func = (RUNTIME_FUNCTION *)((char *)module + (func->UnwindData & ~1));
|
||||
return func;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* lookup_function_info
|
||||
*/
|
||||
static RUNTIME_FUNCTION *lookup_function_info( ULONG64 pc, ULONG64 *base, LDR_MODULE **module )
|
||||
{
|
||||
RUNTIME_FUNCTION *func = NULL;
|
||||
struct dynamic_unwind_entry *entry;
|
||||
ULONG size;
|
||||
|
||||
/* PE module or wine module */
|
||||
if (!LdrFindEntryForAddress( (void *)pc, module ))
|
||||
{
|
||||
*base = (ULONG64)(*module)->BaseAddress;
|
||||
if ((func = RtlImageDirectoryEntryToData( (*module)->BaseAddress, TRUE,
|
||||
IMAGE_DIRECTORY_ENTRY_EXCEPTION, &size )))
|
||||
{
|
||||
/* lookup in function table */
|
||||
func = find_function_info( pc, (*module)->BaseAddress, func, size/sizeof(*func) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*module = NULL;
|
||||
|
||||
RtlEnterCriticalSection( &dynamic_unwind_section );
|
||||
LIST_FOR_EACH_ENTRY( entry, &dynamic_unwind_list, struct dynamic_unwind_entry, entry )
|
||||
{
|
||||
if (pc >= entry->base && pc < entry->end)
|
||||
{
|
||||
*base = entry->base;
|
||||
|
||||
/* use callback or lookup in function table */
|
||||
if (entry->callback)
|
||||
func = entry->callback( pc, entry->context );
|
||||
else
|
||||
func = find_function_info( pc, (HMODULE)entry->base, entry->table, entry->count );
|
||||
break;
|
||||
}
|
||||
}
|
||||
RtlLeaveCriticalSection( &dynamic_unwind_section );
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
static DWORD __cdecl nested_exception_handler( EXCEPTION_RECORD *rec, EXCEPTION_REGISTRATION_RECORD *frame,
|
||||
CONTEXT *context, EXCEPTION_REGISTRATION_RECORD **dispatcher )
|
||||
{
|
||||
|
@ -3436,205 +3333,6 @@ void signal_init_process(void)
|
|||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* RtlAddFunctionTable (NTDLL.@)
|
||||
*/
|
||||
BOOLEAN CDECL RtlAddFunctionTable( RUNTIME_FUNCTION *table, DWORD count, DWORD64 addr )
|
||||
{
|
||||
struct dynamic_unwind_entry *entry;
|
||||
|
||||
TRACE( "%p %u %lx\n", table, count, addr );
|
||||
|
||||
/* NOTE: Windows doesn't check if table is aligned or a NULL pointer */
|
||||
|
||||
entry = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*entry) );
|
||||
if (!entry)
|
||||
return FALSE;
|
||||
|
||||
entry->base = addr;
|
||||
entry->end = addr + (count ? table[count - 1].EndAddress : 0);
|
||||
entry->table = table;
|
||||
entry->count = count;
|
||||
entry->max_count = 0;
|
||||
entry->callback = NULL;
|
||||
entry->context = NULL;
|
||||
|
||||
RtlEnterCriticalSection( &dynamic_unwind_section );
|
||||
list_add_tail( &dynamic_unwind_list, &entry->entry );
|
||||
RtlLeaveCriticalSection( &dynamic_unwind_section );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* RtlInstallFunctionTableCallback (NTDLL.@)
|
||||
*/
|
||||
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) );
|
||||
|
||||
/* 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) );
|
||||
if (!entry)
|
||||
return FALSE;
|
||||
|
||||
entry->base = base;
|
||||
entry->end = base + length;
|
||||
entry->table = (RUNTIME_FUNCTION *)table;
|
||||
entry->count = 0;
|
||||
entry->max_count = 0;
|
||||
entry->callback = callback;
|
||||
entry->context = context;
|
||||
|
||||
RtlEnterCriticalSection( &dynamic_unwind_section );
|
||||
list_add_tail( &dynamic_unwind_list, &entry->entry );
|
||||
RtlLeaveCriticalSection( &dynamic_unwind_section );
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* RtlAddGrowableFunctionTable (NTDLL.@)
|
||||
*/
|
||||
DWORD WINAPI RtlAddGrowableFunctionTable( void **table, RUNTIME_FUNCTION *functions, DWORD count, DWORD max_count,
|
||||
ULONG_PTR base, ULONG_PTR end )
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* RtlGrowFunctionTable (NTDLL.@)
|
||||
*/
|
||||
void WINAPI RtlGrowFunctionTable( void *table, DWORD 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 );
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* RtlDeleteFunctionTable (NTDLL.@)
|
||||
*/
|
||||
BOOLEAN CDECL RtlDeleteFunctionTable( RUNTIME_FUNCTION *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 == table)
|
||||
{
|
||||
to_free = entry;
|
||||
list_remove( &entry->entry );
|
||||
break;
|
||||
}
|
||||
}
|
||||
RtlLeaveCriticalSection( &dynamic_unwind_section );
|
||||
|
||||
if (!to_free)
|
||||
return FALSE;
|
||||
|
||||
RtlFreeHeap( GetProcessHeap(), 0, to_free );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* RtlLookupFunctionEntry (NTDLL.@)
|
||||
*/
|
||||
PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry( ULONG64 pc, ULONG64 *base, UNWIND_HISTORY_TABLE *table )
|
||||
{
|
||||
LDR_MODULE *module;
|
||||
RUNTIME_FUNCTION *func;
|
||||
|
||||
/* FIXME: should use the history table to make things faster */
|
||||
|
||||
func = lookup_function_info( pc, base, &module );
|
||||
if (!func)
|
||||
{
|
||||
*base = 0;
|
||||
if (module)
|
||||
WARN( "no exception table found in module %p pc %lx\n", module->BaseAddress, pc );
|
||||
else
|
||||
WARN( "module not found for %lx\n", pc );
|
||||
}
|
||||
|
||||
return func;
|
||||
}
|
||||
|
||||
static ULONG64 get_int_reg( CONTEXT *context, int reg )
|
||||
{
|
||||
return *(&context->Rax + reg);
|
||||
|
|
|
@ -1248,13 +1248,7 @@ typedef struct _DISPATCHER_CONTEXT
|
|||
typedef LONG (CALLBACK *PEXCEPTION_FILTER)(struct _EXCEPTION_POINTERS*,PVOID);
|
||||
typedef void (CALLBACK *PTERMINATION_HANDLER)(BOOLEAN,PVOID);
|
||||
|
||||
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*);
|
||||
PVOID WINAPI RtlVirtualUnwind(ULONG,ULONG64,ULONG64,RUNTIME_FUNCTION*,CONTEXT*,PVOID*,ULONG64*,KNONVOLATILE_CONTEXT_POINTERS*);
|
||||
|
||||
#define UNW_FLAG_NHANDLER 0
|
||||
#define UNW_FLAG_EHANDLER 1
|
||||
|
@ -1821,12 +1815,11 @@ typedef struct _DISPATCHER_CONTEXT
|
|||
typedef LONG (CALLBACK *PEXCEPTION_FILTER)(struct _EXCEPTION_POINTERS*,DWORD);
|
||||
typedef void (CALLBACK *PTERMINATION_HANDLER)(BOOLEAN,DWORD);
|
||||
|
||||
typedef PRUNTIME_FUNCTION (CALLBACK *PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD,PVOID);
|
||||
PVOID WINAPI RtlVirtualUnwind(DWORD,DWORD,DWORD,RUNTIME_FUNCTION*,CONTEXT*,PVOID*,DWORD*,KNONVOLATILE_CONTEXT_POINTERS*);
|
||||
|
||||
BOOLEAN CDECL RtlAddFunctionTable(RUNTIME_FUNCTION*,DWORD,DWORD);
|
||||
BOOLEAN CDECL RtlDeleteFunctionTable(RUNTIME_FUNCTION*);
|
||||
BOOLEAN CDECL RtlInstallFunctionTableCallback(DWORD,DWORD,DWORD,PGET_RUNTIME_FUNCTION_CALLBACK,PVOID,PCWSTR);
|
||||
PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry(ULONG_PTR,DWORD*,UNWIND_HISTORY_TABLE*);
|
||||
#define UNW_FLAG_NHANDLER 0
|
||||
#define UNW_FLAG_EHANDLER 1
|
||||
#define UNW_FLAG_UHANDLER 2
|
||||
|
||||
#endif /* __arm__ */
|
||||
|
||||
|
@ -2000,11 +1993,11 @@ typedef struct _DISPATCHER_CONTEXT
|
|||
typedef LONG (CALLBACK *PEXCEPTION_FILTER)(struct _EXCEPTION_POINTERS*,DWORD64);
|
||||
typedef void (CALLBACK *PTERMINATION_HANDLER)(BOOLEAN,DWORD64);
|
||||
|
||||
typedef PRUNTIME_FUNCTION (CALLBACK *PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD64,PVOID);
|
||||
PVOID WINAPI RtlVirtualUnwind(DWORD,ULONG_PTR,ULONG_PTR,RUNTIME_FUNCTION*,CONTEXT*,PVOID*,ULONG_PTR*,KNONVOLATILE_CONTEXT_POINTERS*);
|
||||
|
||||
BOOLEAN CDECL RtlAddFunctionTable(RUNTIME_FUNCTION*,DWORD,ULONG_PTR);
|
||||
BOOLEAN CDECL RtlDeleteFunctionTable(RUNTIME_FUNCTION*);
|
||||
BOOLEAN CDECL RtlInstallFunctionTableCallback(ULONG_PTR,ULONG_PTR,DWORD,PGET_RUNTIME_FUNCTION_CALLBACK,PVOID,PCWSTR);
|
||||
#define UNW_FLAG_NHANDLER 0
|
||||
#define UNW_FLAG_EHANDLER 1
|
||||
#define UNW_FLAG_UHANDLER 2
|
||||
|
||||
#endif /* __aarch64__ */
|
||||
|
||||
|
@ -2315,6 +2308,19 @@ typedef struct _WOW64_CONTEXT
|
|||
} WOW64_CONTEXT, *PWOW64_CONTEXT;
|
||||
#include "poppack.h"
|
||||
|
||||
#if defined(__x86_64__) || defined(__arm__) || defined(__aarch64__)
|
||||
|
||||
typedef PRUNTIME_FUNCTION (CALLBACK *PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD_PTR,PVOID);
|
||||
|
||||
BOOLEAN CDECL RtlAddFunctionTable(RUNTIME_FUNCTION*,DWORD,DWORD_PTR);
|
||||
DWORD WINAPI RtlAddGrowableFunctionTable(void**,PRUNTIME_FUNCTION,DWORD,DWORD,ULONG_PTR,ULONG_PTR);
|
||||
BOOLEAN CDECL RtlDeleteFunctionTable(RUNTIME_FUNCTION*);
|
||||
void WINAPI RtlDeleteGrowableFunctionTable(void*);
|
||||
void WINAPI RtlGrowFunctionTable(void*,DWORD);
|
||||
BOOLEAN CDECL RtlInstallFunctionTableCallback(DWORD_PTR,DWORD_PTR,DWORD,PGET_RUNTIME_FUNCTION_CALLBACK,PVOID,PCWSTR);
|
||||
PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry(DWORD_PTR,DWORD_PTR*,UNWIND_HISTORY_TABLE*);
|
||||
void WINAPI RtlUnwindEx(PVOID,PVOID,struct _EXCEPTION_RECORD*,PVOID,CONTEXT*,UNWIND_HISTORY_TABLE*);
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Product types
|
||||
|
|
Loading…
Reference in New Issue