Chip Davis : ntdll: Implement RtlCaptureStackBackTrace() for x86_64.
Alexandre Julliard
julliard at winehq.org
Mon Apr 20 15:01:47 CDT 2020
Module: wine
Branch: oldstable
Commit: e42d4b563451657d00e7153c0d70ca891ce5c5ca
URL: https://source.winehq.org/git/wine.git/?a=commit;h=e42d4b563451657d00e7153c0d70ca891ce5c5ca
Author: Chip Davis <cdavis at codeweavers.com>
Date: Wed Jul 31 16:57:10 2019 -0500
ntdll: Implement RtlCaptureStackBackTrace() for x86_64.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=40868
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47101
Signed-off-by: Chip Davis <cdavis at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>
(cherry picked from commit 4e4aa467752db723cb36ea140860ea24efbe5719)
Signed-off-by: Michael Stefaniuc <mstefani at winehq.org>
---
dlls/ntdll/signal_x86_64.c | 111 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 109 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/signal_x86_64.c b/dlls/ntdll/signal_x86_64.c
index 0e515ff969..c8f55e9ea1 100644
--- a/dlls/ntdll/signal_x86_64.c
+++ b/dlls/ntdll/signal_x86_64.c
@@ -4371,13 +4371,120 @@ __ASM_GLOBAL_FUNC( RtlRaiseException,
"call " __ASM_NAME("RtlRaiseStatus") /* does not return */ );
+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 )
{
- FIXME( "(%d, %d, %p, %p) stub!\n", skip, count, buffer, hash );
- return 0;
+ UNWIND_HISTORY_TABLE table;
+ DISPATCHER_CONTEXT dispatch;
+ CONTEXT context;
+ LDR_MODULE *module;
+ NTSTATUS status;
+ ULONG i;
+ USHORT num_entries = 0;
+
+ TRACE( "(%u, %u, %p, %p)", 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++)
+ {
+ /* FIXME: should use the history table to make things faster */
+
+ dispatch.ImageBase = 0;
+ dispatch.ControlPc = context.Rip;
+ dispatch.ScopeIndex = 0;
+
+ /* first look for PE exception information */
+
+ if ((dispatch.FunctionEntry = lookup_function_info( dispatch.ControlPc, &dispatch.ImageBase, &module )))
+ {
+ RtlVirtualUnwind( UNW_FLAG_NHANDLER, dispatch.ImageBase, dispatch.ControlPc,
+ dispatch.FunctionEntry, &context, &dispatch.HandlerData,
+ &dispatch.EstablisherFrame, NULL );
+ goto unwind_done;
+ }
+
+ /* then look for host system exception information */
+
+ if (!module || (module->Flags & LDR_WINE_INTERNAL))
+ {
+ BOOL got_info = FALSE;
+ struct dwarf_eh_bases bases;
+ const struct dwarf_fde *fde = _Unwind_Find_FDE( (void *)(dispatch.ControlPc - 1), &bases );
+
+ if (fde)
+ {
+ status = dwarf_virtual_unwind( dispatch.ControlPc, &dispatch.EstablisherFrame, &context,
+ fde, &bases, &dispatch.LanguageHandler, &dispatch.HandlerData );
+ if (status != STATUS_SUCCESS) return status;
+ got_info = TRUE;
+ }
+#ifdef HAVE_LIBUNWIND_H
+ else
+ {
+ status = libunwind_virtual_unwind( dispatch.ControlPc, &got_info, &dispatch.EstablisherFrame, &context,
+ &dispatch.LanguageHandler, &dispatch.HandlerData );
+ if (status != STATUS_SUCCESS) return i;
+ }
+#endif
+
+ if (got_info)
+ {
+ dispatch.FunctionEntry = NULL;
+ goto unwind_done;
+ }
+ }
+ else WARN( "exception data not found in %s\n", debugstr_w(module->BaseDllName.Buffer) );
+
+ context.Rip = *(ULONG64 *)context.Rsp;
+ context.Rsp = context.Rsp + sizeof(ULONG64);
+ dispatch.EstablisherFrame = context.Rsp;
+
+ unwind_done:
+ if (!dispatch.EstablisherFrame) break;
+
+ if ((dispatch.EstablisherFrame & 7) ||
+ dispatch.EstablisherFrame < (ULONG64)NtCurrentTeb()->Tib.StackLimit ||
+ dispatch.EstablisherFrame > (ULONG64)NtCurrentTeb()->Tib.StackBase)
+ {
+ ERR( "invalid frame %lx (%p-%p)\n", 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;
}
More information about the wine-cvs
mailing list