Module: wine Branch: master Commit: 38fb2f41ad1347b6e35dc87f6dc358a13d8905cb URL: https://gitlab.winehq.org/wine/wine/-/commit/38fb2f41ad1347b6e35dc87f6dc358a...
Author: Alexandre Julliard julliard@winehq.org Date: Mon Mar 11 16:55:58 2024 +0100
ntdll: Share RtlCaptureStackBackTrace implementation across platforms.
---
dlls/ntdll/exception.c | 21 +++++++++++++++ dlls/ntdll/signal_arm.c | 9 ------- dlls/ntdll/signal_arm64.c | 9 ------- dlls/ntdll/signal_arm64ec.c | 10 ------- dlls/ntdll/signal_i386.c | 30 --------------------- dlls/ntdll/signal_x86_64.c | 64 -------------------------------------------- dlls/ntdll/tests/exception.c | 25 +++++++++++++++++ 7 files changed, 46 insertions(+), 122 deletions(-)
diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c index 75d6f39325c..ac5f403131f 100644 --- a/dlls/ntdll/exception.c +++ b/dlls/ntdll/exception.c @@ -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.@) */ diff --git a/dlls/ntdll/signal_arm.c b/dlls/ntdll/signal_arm.c index 2d75902b12f..a0c9d647a24 100644 --- a/dlls/ntdll/signal_arm.c +++ b/dlls/ntdll/signal_arm.c @@ -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.@) diff --git a/dlls/ntdll/signal_arm64.c b/dlls/ntdll/signal_arm64.c index df588fb64c1..23c01789293 100644 --- a/dlls/ntdll/signal_arm64.c +++ b/dlls/ntdll/signal_arm64.c @@ -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.@) diff --git a/dlls/ntdll/signal_arm64ec.c b/dlls/ntdll/signal_arm64ec.c index 02e6dc009bf..643ec3331de 100644 --- a/dlls/ntdll/signal_arm64ec.c +++ b/dlls/ntdll/signal_arm64ec.c @@ -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; diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c index cade0c973c2..13e5be6af68 100644 --- a/dlls/ntdll/signal_i386.c +++ b/dlls/ntdll/signal_i386.c @@ -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.@) */ diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c index 1e928cad2c9..d37cd741c09 100644 --- a/dlls/ntdll/signal_x86_64.c +++ b/dlls/ntdll/signal_x86_64.c @@ -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.@) diff --git a/dlls/ntdll/tests/exception.c b/dlls/ntdll/tests/exception.c index 5ccd1af3906..e4922aac616 100644 --- a/dlls/ntdll/tests/exception.c +++ b/dlls/ntdll/tests/exception.c @@ -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); }