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/r…
==============================================================================
--- 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;
+}
+