Commit 38fb2f41 authored by Alexandre Julliard's avatar Alexandre Julliard

ntdll: Share RtlCaptureStackBackTrace implementation across platforms.

parent 2bf209bb
......@@ -510,6 +510,27 @@ __ASM_GLOBAL_IMPORT(IsBadStringPtrA)
__ASM_GLOBAL_IMPORT(IsBadStringPtrW)
#endif
/*************************************************************************
* RtlCaptureStackBackTrace (NTDLL.@)
*/
USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, void **buffer, ULONG *hash_ret )
{
ULONG i, ret, hash;
TRACE( "(%lu, %lu, %p, %p)\n", skip, count, buffer, hash_ret );
skip++; /* skip our own frame */
ret = RtlWalkFrameChain( buffer, count + skip, skip << 8 );
if (hash_ret)
{
for (i = hash = 0; i < ret; i++) hash += (ULONG_PTR)buffer[i];
*hash_ret = hash;
}
return ret;
}
/**********************************************************************
* RtlGetEnabledExtendedFeatures (NTDLL.@)
*/
......
......@@ -737,15 +737,6 @@ __ASM_GLOBAL_FUNC( RtlRaiseException,
"bl " __ASM_NAME("NtRaiseException") "\n\t"
"bl " __ASM_NAME("RtlRaiseStatus") )
/*************************************************************************
* RtlCaptureStackBackTrace (NTDLL.@)
*/
USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
{
FIXME( "(%ld, %ld, %p, %p) stub!\n", skip, count, buffer, hash );
return 0;
}
/***********************************************************************
* _setjmp (NTDLL.@)
......
......@@ -849,15 +849,6 @@ __ASM_GLOBAL_FUNC( RtlRaiseException,
"bl " __ASM_NAME("NtRaiseException") "\n\t"
"bl " __ASM_NAME("RtlRaiseStatus") /* does not return */ );
/*************************************************************************
* RtlCaptureStackBackTrace (NTDLL.@)
*/
USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
{
FIXME( "(%ld, %ld, %p, %p) stub!\n", skip, count, buffer, hash );
return 0;
}
/***********************************************************************
* _setjmpex (NTDLL.@)
......
......@@ -2040,16 +2040,6 @@ EXCEPTION_DISPOSITION WINAPI __C_specific_handler( EXCEPTION_RECORD *rec,
}
/*************************************************************************
* RtlCaptureStackBackTrace (NTDLL.@)
*/
USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
{
FIXME( "not implemented\n" );
return 0;
}
static int code_match( BYTE *code, const BYTE *seq, size_t len )
{
for ( ; len; len--, code++, seq++) if (*seq && *code != *seq) return 0;
......
......@@ -474,36 +474,6 @@ ULONG WINAPI RtlWalkFrameChain( void **buffer, ULONG count, ULONG flags )
}
/*************************************************************************
* RtlCaptureStackBackTrace (NTDLL.@)
*/
USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
{
CONTEXT context;
ULONG i;
ULONG *frame;
RtlCaptureContext( &context );
if (hash) *hash = 0;
frame = (ULONG *)context.Ebp;
while (skip--)
{
if (!is_valid_frame( (ULONG_PTR)frame )) return 0;
frame = (ULONG *)*frame;
}
for (i = 0; i < count; i++)
{
if (!is_valid_frame( (ULONG_PTR)frame )) break;
buffer[i] = (void *)frame[1];
if (hash) *hash += frame[1];
frame = (ULONG *)*frame;
}
return i;
}
/***********************************************************************
* RtlUserThreadStart (NTDLL.@)
*/
......
......@@ -988,70 +988,6 @@ ULONG WINAPI RtlWalkFrameChain( void **buffer, ULONG count, ULONG flags )
}
static inline ULONG hash_pointers( void **ptrs, ULONG count )
{
/* Based on MurmurHash2, which is in the public domain */
static const ULONG m = 0x5bd1e995;
static const ULONG r = 24;
ULONG hash = count * sizeof(void*);
for (; count > 0; ptrs++, count--)
{
ULONG_PTR data = (ULONG_PTR)*ptrs;
ULONG k1 = (ULONG)(data & 0xffffffff), k2 = (ULONG)(data >> 32);
k1 *= m;
k1 = (k1 ^ (k1 >> r)) * m;
k2 *= m;
k2 = (k2 ^ (k2 >> r)) * m;
hash = (((hash * m) ^ k1) * m) ^ k2;
}
hash = (hash ^ (hash >> 13)) * m;
return hash ^ (hash >> 15);
}
/*************************************************************************
* RtlCaptureStackBackTrace (NTDLL.@)
*/
USHORT WINAPI RtlCaptureStackBackTrace( ULONG skip, ULONG count, PVOID *buffer, ULONG *hash )
{
UNWIND_HISTORY_TABLE table;
DISPATCHER_CONTEXT dispatch;
CONTEXT context;
NTSTATUS status;
ULONG i;
USHORT num_entries = 0;
TRACE( "(%lu, %lu, %p, %p)\n", skip, count, buffer, hash );
RtlCaptureContext( &context );
dispatch.TargetIp = 0;
dispatch.ContextRecord = &context;
dispatch.HistoryTable = &table;
if (hash) *hash = 0;
for (i = 0; i < skip + count; i++)
{
status = virtual_unwind( UNW_FLAG_NHANDLER, &dispatch, &context );
if (status != STATUS_SUCCESS) return i;
if (!dispatch.EstablisherFrame) break;
if (!is_valid_frame( dispatch.EstablisherFrame ))
{
ERR( "invalid frame %p (%p-%p)\n", (void *)dispatch.EstablisherFrame,
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
break;
}
if (context.Rsp == (ULONG64)NtCurrentTeb()->Tib.StackBase) break;
if (i >= skip) buffer[num_entries++] = (void *)context.Rip;
}
if (hash && num_entries > 0) *hash = hash_pointers( buffer, num_entries );
TRACE( "captured %hu frames\n", num_entries );
return num_entries;
}
/***********************************************************************
* _setjmp (NTDLL.@)
* _setjmpex (NTDLL.@)
......
......@@ -10287,6 +10287,30 @@ static void test_set_live_context(void)
}
#endif
static void test_backtrace(void)
{
void *buffer[1024];
WCHAR *p, name[MAX_PATH];
void *module;
ULONG hash, hash_expect;
int i, count = RtlCaptureStackBackTrace( 0, 1024, buffer, &hash );
ok( count > 1, "got %u entries\n", count );
for (i = hash_expect = 0; i < count; i++) hash_expect += (ULONG_PTR)buffer[i];
ok( hash == hash_expect, "hash mismatch %lx / %lx\n", hash, hash_expect );
RtlPcToFileHeader( buffer[0], &module );
ok( module == GetModuleHandleA(0), "wrong module %p/%p for %p\n",
module, GetModuleHandleA(0), buffer[0]);
if (count && !buffer[count - 1]) count--; /* win11 32-bit */
RtlPcToFileHeader( buffer[count - 1], &module );
GetModuleFileNameW( module, name, sizeof(name) );
if ((p = wcsrchr( name, '\\' ))) p++;
else p = name;
ok( !wcsicmp( p, L"ntdll.dll" ), "wrong module %p %s for frame %u %p\n",
module, debugstr_w(name), count - 1, buffer[count - 1] );
}
START_TEST(exception)
{
HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
......@@ -10562,5 +10586,6 @@ START_TEST(exception)
test_suspend_thread();
test_suspend_process();
test_unload_trace();
test_backtrace();
VirtualFree(code_mem, 0, MEM_RELEASE);
}
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