Big merge: thanks alex and greatlord. Not a complete merge but most
[reactos.git] / reactos / lib / rtl / exception.c
index e4066e6..c992011 100644 (file)
@@ -110,8 +110,96 @@ RtlRaiseStatus(NTSTATUS Status)
 }
 
 /*
-* @unimplemented
-*/
+ * @implemented
+ */
+ULONG
+NTAPI
+RtlWalkFrameChain(OUT PVOID *Callers,
+                  IN ULONG Count,
+                  IN ULONG Flags)
+{
+    PULONG Stack, NewStack;
+    ULONG Eip;
+    ULONG_PTR StackBegin, StackEnd;
+    BOOLEAN Result, StopSearch = FALSE;
+    ULONG i = 0;
+
+    /* Get current EBP */
+#ifdef _M_IX86
+#if defined __GNUC__
+    __asm__("mov %%ebp, %0" : "=r" (Stack) : );
+#elif defined(_MSC_VER)
+    __asm mov Stack, ebp
+#endif
+#elif defined(_M_PPC)
+    __asm__("mr %0, %%r1" : "=r" (Stack) : );
+#endif
+
+    /* Set it as the stack begin limit as well */
+    StackBegin = (ULONG_PTR)Stack;
+
+    /* Check if we're called for non-logging mode */
+    if (!Flags)
+    {
+        /* Get the actual safe limits */
+        Result = RtlpCaptureStackLimits((ULONG_PTR)Stack,
+                                        &StackBegin,
+                                        &StackEnd);
+        if (!Result) return 0;
+    }
+
+    /* Loop the frames */
+    for (i = 0; i < Count; i++)
+    {
+        /* Check if we're past the stack */
+        if ((ULONG_PTR)Stack >= StackEnd) break;
+
+        /* Check if this is the first entry */
+#if 0
+        if (!i)
+        {
+            if ((ULONG_PTR)Stack != StackBegin) break;
+        }
+        else
+        {
+            if ((ULONG_PTR)Stack == StackBegin) break;
+        }
+#endif
+
+        /* Make sure there's enough frames */
+        if ((StackEnd - (ULONG_PTR)Stack) < (2 * sizeof(ULONG_PTR))) break;
+
+        /* Get new stack and EIP */
+        NewStack = (PULONG)Stack[0];
+        Eip = Stack[1];
+
+        /* Check if the new pointer is above the oldone and past the end */
+        if (!((Stack < NewStack) && ((ULONG_PTR)NewStack < StackEnd)))
+        {
+            /* Stop searching after this entry */
+            StopSearch = TRUE;
+        }
+
+        /* Also make sure that the EIP isn't a stack address */
+        if ((StackBegin < Eip) && (Eip < StackEnd)) break;
+
+        /* Save this frame */
+        Callers[i] = (PVOID)Eip;
+
+        /* Check if we should continue */
+        if (StopSearch) break;
+
+        /* Move to the next stack */
+        Stack = NewStack;
+    }
+
+    /* Return frames parsed */
+    return i;
+}
+
+/*
+ * @implemented
+ */
 USHORT
 NTAPI
 RtlCaptureStackBackTrace(IN ULONG FramesToSkip,
@@ -119,21 +207,39 @@ RtlCaptureStackBackTrace(IN ULONG FramesToSkip,
                          OUT PVOID *BackTrace,
                          OUT PULONG BackTraceHash OPTIONAL)
 {
-    UNIMPLEMENTED;
-    return 0;
-}
+    PVOID Frames[2 * 64];
+    ULONG FrameCount;
+    ULONG Hash = 0, i;
 
-/*
-* @unimplemented
-*/
-ULONG
-NTAPI
-RtlWalkFrameChain(OUT PVOID *Callers,
-                  IN ULONG Count,
-                  IN ULONG Flags)
-{
-    UNIMPLEMENTED;
-    return 0;
+    /* Skip a frame for the caller */
+    FramesToSkip++;
+
+    /* Don't go past the limit */
+    if ((FramesToCapture + FramesToSkip) >= 128) return 0;
+
+    /* Do the back trace */
+    FrameCount = RtlWalkFrameChain(Frames, FramesToCapture + FramesToSkip, 0);
+
+    /* Make sure we're not skipping all of them */
+    if (FrameCount <= FramesToSkip) return 0;
+
+    /* Loop all the frames */
+    for (i = 0; i < FramesToCapture; i++)
+    {
+        /* Don't go past the limit */
+        if ((FramesToSkip + i) >= FrameCount) break;
+
+        /* Save this entry and hash it */
+        BackTrace[i] = Frames[FramesToSkip + i];
+        Hash += PtrToUlong(BackTrace[i]);
+    }
+
+    /* Write the hash */
+    if (BackTraceHash) *BackTraceHash = Hash;
+
+    /* Clear the other entries and return count */
+    RtlFillMemoryUlong(Frames, 128, 0);
+    return (USHORT)i;
 }
 
 /*