ntdll: Share RtlCaptureStackBackTrace implementation across platforms.
This commit is contained in:
parent
2bf209bb4f
commit
38fb2f41ad
7 changed files with 46 additions and 122 deletions
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue