[ros-diffs] [tkreuzer] 37332: Initial Implementations of RtlVirtualUnwind and RtlWalkFrameChain. They are not yet perfect, but unwinding works!

tkreuzer at svn.reactos.org tkreuzer at svn.reactos.org
Thu Nov 13 05:17:53 CET 2008


Author: tkreuzer
Date: Wed Nov 12 22:17:53 2008
New Revision: 37332

URL: http://svn.reactos.org/svn/reactos?rev=37332&view=rev
Log:
Initial Implementations of RtlVirtualUnwind and RtlWalkFrameChain. They are not yet perfect, but unwinding works!

Modified:
    branches/ros-amd64-bringup/reactos/lib/rtl/amd64/unwind.c

Modified: branches/ros-amd64-bringup/reactos/lib/rtl/amd64/unwind.c
URL: http://svn.reactos.org/svn/reactos/branches/ros-amd64-bringup/reactos/lib/rtl/amd64/unwind.c?rev=37332&r1=37331&r2=37332&view=diff
==============================================================================
--- branches/ros-amd64-bringup/reactos/lib/rtl/amd64/unwind.c [iso-8859-1] (original)
+++ branches/ros-amd64-bringup/reactos/lib/rtl/amd64/unwind.c [iso-8859-1] Wed Nov 12 22:17:53 2008
@@ -15,6 +15,48 @@
 #define UNWIND_HISTORY_TABLE_GLOBAL 1
 #define UNWIND_HISTORY_TABLE_LOCAL 2
 
+#define UWOP_PUSH_NONVOL 0
+#define UWOP_ALLOC_LARGE 1
+#define UWOP_ALLOC_SMALL 2
+#define UWOP_SET_FPREG 3
+#define UWOP_SAVE_NONVOL 4
+#define UWOP_SAVE_NONVOL_FAR 5
+#define UWOP_SAVE_XMM 6
+#define UWOP_SAVE_XMM_FAR 7
+#define UWOP_SAVE_XMM128 8
+#define UWOP_SAVE_XMM128_FAR 9
+#define UWOP_PUSH_MACHFRAME 10
+
+typedef unsigned char UBYTE;
+
+typedef union _UNWIND_CODE
+{
+    struct
+    {
+        UBYTE CodeOffset;
+        UBYTE UnwindOp:4;
+        UBYTE OpInfo:4;
+    };
+    USHORT FrameOffset;
+} UNWIND_CODE, *PUNWIND_CODE;
+
+typedef struct _UNWIND_INFO
+{
+    UBYTE Version:3;
+    UBYTE Flags:5;
+    UBYTE SizeOfProlog;
+    UBYTE CountOfCodes;
+    UBYTE FrameRegister:4;
+    UBYTE FrameOffset:4;
+    UNWIND_CODE UnwindCode[1];
+/*    union {
+        OPTIONAL ULONG ExceptionHandler;
+        OPTIONAL ULONG FunctionEntry;
+    };
+    OPTIONAL ULONG ExceptionData[]; 
+*/
+} UNWIND_INFO, *PUNWIND_INFO;
+
 PVOID
 NTAPI
 RtlpLookupModuleBase(
@@ -119,6 +161,12 @@
     return NULL;
 }
 
+void
+FORCEINLINE
+SetReg(PCONTEXT Context, UCHAR Reg, ULONG64 Value)
+{
+    ((PULONG64)(&Context->Rax))[Reg] = Value;
+}
 
 PEXCEPTION_ROUTINE
 NTAPI
@@ -127,12 +175,126 @@
     IN ULONG64 ImageBase,
     IN ULONG64 ControlPc,
     IN PRUNTIME_FUNCTION FunctionEntry,
-    IN OUT PCONTEXT ContextRecord,
+    IN OUT PCONTEXT Context,
     OUT PVOID *HandlerData,
     OUT PULONG64 EstablisherFrame,
     IN OUT PKNONVOLATILE_CONTEXT_POINTERS ContextPointers)
 {
-    UNIMPLEMENTED;
+    PUNWIND_INFO UnwindInfo;
+    ULONG CodeOffset;
+    ULONG i;
+    UNWIND_CODE UnwindCode;
+    UCHAR Reg;
+
+    /* Use relative virtual address */
+    ControlPc -= ImageBase;
+
+    /* Sanity checks */
+    if ( (ControlPc < FunctionEntry->BeginAddress) ||
+         (ControlPc >= FunctionEntry->EndAddress) )
+    {
+        return NULL;
+    }
+
+    /* Get a pointer to the unwind info */
+    UnwindInfo = RVA(ImageBase, FunctionEntry->UnwindData);
+
+    /* Calculate relative offset to function start */
+    CodeOffset = ControlPc - FunctionEntry->BeginAddress;
+
+    /* Skip all Ops with an offset greater than the current Offset */
+    i = 0;
+    while (i < UnwindInfo->CountOfCodes &&
+           CodeOffset < UnwindInfo->UnwindCode[i].CodeOffset)
+    {
+        UnwindCode = UnwindInfo->UnwindCode[i];
+        switch (UnwindCode.UnwindOp)
+        {
+            case UWOP_SAVE_NONVOL:
+            case UWOP_SAVE_XMM:
+            case UWOP_SAVE_XMM128:
+                i += 2;
+                break;
+
+            case UWOP_SAVE_NONVOL_FAR:
+            case UWOP_SAVE_XMM_FAR:
+            case UWOP_SAVE_XMM128_FAR:
+                i += 3;
+                break;
+
+            case UWOP_ALLOC_LARGE:
+                i += UnwindCode.OpInfo ? 3 : 2;
+                break;
+
+            default:
+                i++;
+        }
+    }
+
+    /* Process the left Ops */
+    while (i < UnwindInfo->CountOfCodes)
+    {
+        UnwindCode = UnwindInfo->UnwindCode[i];
+        switch (UnwindCode.UnwindOp)
+        {
+            case UWOP_PUSH_NONVOL:
+                Reg = UnwindCode.OpInfo;
+                SetReg(Context, Reg, *(DWORD64*)Context->Rsp);
+                Context->Rsp += sizeof(DWORD64);
+                i++;
+                break;
+
+            case UWOP_ALLOC_LARGE:
+                if (UnwindCode.OpInfo)
+                {
+                    ULONG Offset = *(ULONG*)(&UnwindInfo->UnwindCode[i+1]);
+                    Context->Rsp += Offset;
+                    i += 3;
+                }
+                else
+                {
+                    USHORT Offset = UnwindInfo->UnwindCode[i+1].FrameOffset;
+                    Context->Rsp += Offset * 8;
+                    i += 2;
+                }
+                break;
+
+            case UWOP_ALLOC_SMALL:
+                Context->Rsp += (UnwindCode.OpInfo + 1) * 8;
+                i++;
+                break;
+
+            case UWOP_SET_FPREG:
+                i++;
+                break;
+
+            case UWOP_SAVE_NONVOL:
+                i += 2;
+                break;
+
+            case UWOP_SAVE_NONVOL_FAR:
+                i += 3;
+                break;
+
+            case UWOP_SAVE_XMM:
+                i += 2;
+                break;
+
+            case UWOP_SAVE_XMM_FAR:
+                i += 3;
+            case UWOP_SAVE_XMM128:
+                i += 2;
+            case UWOP_SAVE_XMM128_FAR:
+                i += 3;
+            case UWOP_PUSH_MACHFRAME:
+                i += 1;
+        }
+    }
+
+    /* Unwind is finished, pop new Rip from Stack */
+    Context->Rip = *(DWORD64*)Context->Rsp;
+    Context->Rsp += 8;
+
     return 0;
 }
 
@@ -150,4 +312,63 @@
     return;
 }
 
-
+ULONG
+NTAPI
+RtlWalkFrameChain(OUT PVOID *Callers,
+                  IN ULONG Count,
+                  IN ULONG Flags)
+{
+    CONTEXT Context;
+    ULONG64 ControlPc, ImageBase, EstablisherFrame;
+    ULONG64 StackBegin, StackEnd;
+    PVOID HandlerData;
+    INT i;
+    PRUNTIME_FUNCTION FunctionEntry;
+DPRINT1("RtlWalkFrameChain called\n");
+    RtlCaptureContext(&Context);
+
+    ControlPc = Context.Rip;
+
+    RtlpGetStackLimits(&StackBegin, &StackEnd);
+
+    /* Check if we want the user-mode stack frame */
+    if (Flags == 1)
+    {
+    }
+
+    /* Loop the frames */
+    for (i = 0; i < Count; i++)
+    {
+        /* Lookup the FunctionEntry for the current ControlPc */
+        FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);
+
+        /* Is this a leaf function? */
+        if (!FunctionEntry)
+        {
+            Context.Rip = *(ULONG64*)Context.Rsp;
+            Context.Rsp += sizeof(ULONG64);
+            DPRINT1("leaf funtion, new Rip = %p, new Rsp = %p\n", (PVOID)Context.Rip, (PVOID)Context.Rsp);
+        }
+        else
+        {
+            RtlVirtualUnwind(0,
+                             ImageBase,
+                             ControlPc,
+                             FunctionEntry,
+                             &Context,
+                             &HandlerData,
+                             &EstablisherFrame,
+                             NULL);
+            DPRINT1("normal funtion, new Rip = %p, new Rsp = %p\n", (PVOID)Context.Rip, (PVOID)Context.Rsp);
+        }
+
+        ControlPc = Context.Rip;
+        /* Save this frame */
+
+        Callers[i] = (PVOID)ControlPc;
+
+    }
+
+    return i;
+}
+



More information about the Ros-diffs mailing list