ReactOS 0.4.17-dev-301-g9127a53
unwind.c File Reference
#include <rtl.h>
#include <debug.h>
Include dependency graph for unwind.c:

Go to the source code of this file.

Classes

union  _UNWIND_CODE
 
struct  _UNWIND_INFO
 

Macros

#define NDEBUG
 
#define UNWIND_HISTORY_TABLE_NONE   0
 
#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_EPILOG   6
 
#define UWOP_SPARE_CODE   7
 
#define UWOP_SAVE_XMM128   8
 
#define UWOP_SAVE_XMM128_FAR   9
 
#define UWOP_PUSH_MACHFRAME   10
 

Typedefs

typedef unsigned char UBYTE
 
typedef union _UNWIND_CODE UNWIND_CODE
 
typedef union _UNWIND_CODEPUNWIND_CODE
 
typedef struct _UNWIND_INFO UNWIND_INFO
 
typedef struct _UNWIND_INFOPUNWIND_INFO
 

Functions

PRUNTIME_FUNCTION NTAPI RtlLookupFunctionTable (IN DWORD64 ControlPc, OUT PDWORD64 ImageBase, OUT PULONG Length)
 Locates the table of RUNTIME_FUNCTION entries for a code address.
 
PRUNTIME_FUNCTION NTAPI RtlpLookupDynamicFunctionEntry (_In_ DWORD64 ControlPc, _Out_ PDWORD64 ImageBase, _In_ PUNWIND_HISTORY_TABLE HistoryTable)
 
PRUNTIME_FUNCTION NTAPI RtlLookupFunctionEntry (IN DWORD64 ControlPc, OUT PDWORD64 ImageBase, OUT PUNWIND_HISTORY_TABLE HistoryTable)
 Locates the RUNTIME_FUNCTION entry corresponding to a code address. https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtllookupfunctionentry.
 
static __inline ULONG UnwindOpSlots (_In_ UNWIND_CODE UnwindCode)
 
static __inline void SetReg (_Inout_ PCONTEXT Context, _In_ BYTE Reg, _In_ DWORD64 Value)
 
static __inline void SetRegFromStackValue (_Inout_ PCONTEXT Context, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ BYTE Reg, _In_ PDWORD64 ValuePointer)
 
static __inline DWORD64 GetReg (_In_ PCONTEXT Context, _In_ BYTE Reg)
 
static __inline void PopReg (_Inout_ PCONTEXT Context, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ BYTE Reg)
 
static __inline void SetXmmReg (_Inout_ PCONTEXT Context, _In_ BYTE Reg, _In_ M128A Value)
 
static __inline void SetXmmRegFromStackValue (_Out_ PCONTEXT Context, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ BYTE Reg, _In_ M128A *ValuePointer)
 
static __inline M128A GetXmmReg (PCONTEXT Context, BYTE Reg)
 
static __inline BOOLEAN RtlpTryToUnwindEpilog (_Inout_ PCONTEXT Context, _In_ ULONG64 ControlPc, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ ULONG64 ImageBase, _In_ PRUNTIME_FUNCTION FunctionEntry)
 Helper function that tries to unwind epilog instructions.
 
static ULONG64 GetEstablisherFrame (_In_ PCONTEXT Context, _In_ PUNWIND_INFO UnwindInfo, _In_ ULONG_PTR CodeOffset)
 
PEXCEPTION_ROUTINE NTAPI RtlVirtualUnwind (_In_ ULONG HandlerType, _In_ ULONG64 ImageBase, _In_ ULONG64 ControlPc, _In_ PRUNTIME_FUNCTION FunctionEntry, _Inout_ PCONTEXT Context, _Outptr_ PVOID *HandlerData, _Out_ PULONG64 EstablisherFrame, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers)
 
static __inline BOOL RtlpIsStackPointerValid (_In_ ULONG64 StackPointer, _In_ ULONG64 LowLimit, _In_ ULONG64 HighLimit)
 
EXCEPTION_DISPOSITION RtlpExecuteHandlerForUnwindHandler (_Inout_ PEXCEPTION_RECORD ExceptionRecord, _In_ PVOID EstablisherFrame, _Inout_ PCONTEXT ContextRecord, _In_ PDISPATCHER_CONTEXT DispatcherContext)
 
BOOLEAN NTAPI RtlpUnwindInternal (_In_opt_ PVOID TargetFrame, _In_opt_ PVOID TargetIp, _In_ PEXCEPTION_RECORD ExceptionRecord, _In_ PVOID ReturnValue, _In_ PCONTEXT ContextRecord, _In_opt_ struct _UNWIND_HISTORY_TABLE *HistoryTable, _In_ ULONG HandlerType)
 
VOID NTAPI RtlUnwindEx (_In_opt_ PVOID TargetFrame, _In_opt_ PVOID TargetIp, _In_opt_ PEXCEPTION_RECORD ExceptionRecord, _In_ PVOID ReturnValue, _In_ PCONTEXT ContextRecord, _In_opt_ struct _UNWIND_HISTORY_TABLE *HistoryTable)
 
VOID NTAPI RtlUnwind (_In_opt_ PVOID TargetFrame, _In_opt_ PVOID TargetIp, _In_opt_ PEXCEPTION_RECORD ExceptionRecord, _In_ PVOID ReturnValue)
 
ULONG NTAPI RtlWalkFrameChain (OUT PVOID *Callers, IN ULONG Count, IN ULONG Flags)
 
VOID NTAPI RtlGetCallersAddress (OUT PVOID *CallersAddress, OUT PVOID *CallersCaller)
 
static VOID RtlpCaptureNonVolatileContextPointers (_Out_ PKNONVOLATILE_CONTEXT_POINTERS NonvolatileContextPointers, _In_ ULONG64 TargetFrame)
 
VOID RtlGetUnwindContext (_Out_ PCONTEXT Context, _In_ DWORD64 TargetFrame)
 
VOID RtlSetUnwindContext (_In_ PCONTEXT Context, _In_ DWORD64 TargetFrame)
 
VOID RtlpRestoreContextInternal (_In_ PCONTEXT ContextRecord)
 
VOID RtlRestoreContext (_In_ PCONTEXT ContextRecord, _In_ PEXCEPTION_RECORD ExceptionRecord)
 

Macro Definition Documentation

◆ NDEBUG

#define NDEBUG

Definition at line 12 of file unwind.c.

◆ UNWIND_HISTORY_TABLE_GLOBAL

#define UNWIND_HISTORY_TABLE_GLOBAL   1

Definition at line 16 of file unwind.c.

◆ UNWIND_HISTORY_TABLE_LOCAL

#define UNWIND_HISTORY_TABLE_LOCAL   2

Definition at line 17 of file unwind.c.

◆ UNWIND_HISTORY_TABLE_NONE

#define UNWIND_HISTORY_TABLE_NONE   0

Definition at line 15 of file unwind.c.

◆ UWOP_ALLOC_LARGE

#define UWOP_ALLOC_LARGE   1

Definition at line 20 of file unwind.c.

◆ UWOP_ALLOC_SMALL

#define UWOP_ALLOC_SMALL   2

Definition at line 21 of file unwind.c.

◆ UWOP_EPILOG

#define UWOP_EPILOG   6

Definition at line 29 of file unwind.c.

◆ UWOP_PUSH_MACHFRAME

#define UWOP_PUSH_MACHFRAME   10

Definition at line 34 of file unwind.c.

◆ UWOP_PUSH_NONVOL

#define UWOP_PUSH_NONVOL   0

Definition at line 19 of file unwind.c.

◆ UWOP_SAVE_NONVOL

#define UWOP_SAVE_NONVOL   4

Definition at line 23 of file unwind.c.

◆ UWOP_SAVE_NONVOL_FAR

#define UWOP_SAVE_NONVOL_FAR   5

Definition at line 24 of file unwind.c.

◆ UWOP_SAVE_XMM128

#define UWOP_SAVE_XMM128   8

Definition at line 32 of file unwind.c.

◆ UWOP_SAVE_XMM128_FAR

#define UWOP_SAVE_XMM128_FAR   9

Definition at line 33 of file unwind.c.

◆ UWOP_SET_FPREG

#define UWOP_SET_FPREG   3

Definition at line 22 of file unwind.c.

◆ UWOP_SPARE_CODE

#define UWOP_SPARE_CODE   7

Definition at line 30 of file unwind.c.

Typedef Documentation

◆ PUNWIND_CODE

typedef union _UNWIND_CODE * PUNWIND_CODE

◆ PUNWIND_INFO

◆ UBYTE

typedef unsigned char UBYTE

Definition at line 37 of file unwind.c.

◆ UNWIND_CODE

typedef union _UNWIND_CODE UNWIND_CODE

◆ UNWIND_INFO

Function Documentation

◆ GetEstablisherFrame()

static ULONG64 GetEstablisherFrame ( _In_ PCONTEXT  Context,
_In_ PUNWIND_INFO  UnwindInfo,
_In_ ULONG_PTR  CodeOffset 
)
static

https://docs.microsoft.com/en-us/cpp/build/unwind-data-definitions-in-c

Definition at line 433 of file unwind.c.

437{
438 ULONG i;
439
440 /* Check if we have a frame register */
441 if (UnwindInfo->FrameRegister == 0)
442 {
443 /* No frame register means we use Rsp */
444 return Context->Rsp;
445 }
446
447 if ((CodeOffset >= UnwindInfo->SizeOfProlog) ||
448 ((UnwindInfo->Flags & UNW_FLAG_CHAININFO) != 0))
449 {
450 return GetReg(Context, UnwindInfo->FrameRegister) -
451 UnwindInfo->FrameOffset * 16;
452 }
453
454 /* Loop all unwind ops */
455 for (i = 0;
456 i < UnwindInfo->CountOfCodes;
457 i += UnwindOpSlots(UnwindInfo->UnwindCode[i]))
458 {
459 /* Skip codes past our code offset */
460 if (UnwindInfo->UnwindCode[i].CodeOffset > CodeOffset)
461 {
462 continue;
463 }
464
465 /* Check for SET_FPREG */
466 if (UnwindInfo->UnwindCode[i].UnwindOp == UWOP_SET_FPREG)
467 {
468 return GetReg(Context, UnwindInfo->FrameRegister) -
469 UnwindInfo->FrameOffset * 16;
470 }
471 }
472
473 return Context->Rsp;
474}
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
static __inline ULONG UnwindOpSlots(_In_ UNWIND_CODE UnwindCode)
Definition: unwind.c:177
static __inline DWORD64 GetReg(_In_ PCONTEXT Context, _In_ BYTE Reg)
Definition: unwind.c:237
#define UWOP_SET_FPREG
Definition: unwind.c:22
_In_ PVOID Context
Definition: storport.h:2269
uint32_t ULONG
Definition: typedefs.h:59

Referenced by RtlVirtualUnwind().

◆ GetReg()

static __inline DWORD64 GetReg ( _In_ PCONTEXT  Context,
_In_ BYTE  Reg 
)
static

Definition at line 237 of file unwind.c.

240{
241 return ((DWORD64*)(&Context->Rax))[Reg];
242}
uint64_t DWORD64
Definition: typedefs.h:67

Referenced by GetEstablisherFrame(), RtlpTryToUnwindEpilog(), and RtlVirtualUnwind().

◆ GetXmmReg()

static __inline M128A GetXmmReg ( PCONTEXT  Context,
BYTE  Reg 
)
static

Definition at line 286 of file unwind.c.

287{
288 return ((M128A*)(&Context->Xmm0))[Reg];
289}
M128A
Definition: ketypes.h:1008

◆ PopReg()

static __inline void PopReg ( _Inout_ PCONTEXT  Context,
_Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS  ContextPointers,
_In_ BYTE  Reg 
)
static

Definition at line 247 of file unwind.c.

251{
252 SetRegFromStackValue(Context, ContextPointers, Reg, (PDWORD64)Context->Rsp);
253 Context->Rsp += sizeof(DWORD64);
254}
static __inline void SetRegFromStackValue(_Inout_ PCONTEXT Context, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ BYTE Reg, _In_ PDWORD64 ValuePointer)
Definition: unwind.c:221
uint64_t * PDWORD64
Definition: typedefs.h:67

Referenced by RtlpTryToUnwindEpilog(), and RtlVirtualUnwind().

◆ RtlGetCallersAddress()

VOID NTAPI RtlGetCallersAddress ( OUT PVOID CallersAddress,
OUT PVOID CallersCaller 
)

RtlGetCallersAddress http://undocumented.ntinternals.net/UserMode/Undocumented%20Functions/Debug/RtlGetCallersAddress.html

Definition at line 1139 of file unwind.c.

1142{
1143 PVOID Callers[4];
1144 ULONG Number;
1145
1146 /* Get callers:
1147 * RtlWalkFrameChain -> RtlGetCallersAddress -> x -> y */
1148 Number = RtlWalkFrameChain(Callers, 4, 0);
1149
1150 *CallersAddress = (Number >= 3) ? Callers[2] : NULL;
1151 *CallersCaller = (Number == 4) ? Callers[3] : NULL;
1152
1153 return;
1154}
#define NULL
Definition: types.h:112
_In_ ULONG Number
Definition: haltypes.h:1872
ULONG NTAPI RtlWalkFrameChain(OUT PVOID *Callers, IN ULONG Count, IN ULONG Flags)
Definition: unwind.c:1024

◆ RtlGetUnwindContext()

VOID RtlGetUnwindContext ( _Out_ PCONTEXT  Context,
_In_ DWORD64  TargetFrame 
)

Definition at line 1210 of file unwind.c.

1213{
1214 KNONVOLATILE_CONTEXT_POINTERS ContextPointers;
1215 ULONG ContextFlags = Context->ContextFlags & ~CONTEXT_AMD64;
1216
1217 /* Capture pointers to the non-volatiles up to the target frame */
1218 RtlpCaptureNonVolatileContextPointers(&ContextPointers, TargetFrame);
1219
1220 /* Copy the nonvolatiles from the captured locations */
1221 if (ContextFlags & CONTEXT_INTEGER)
1222 {
1223 Context->Rbx = *ContextPointers.Rbx;
1224 Context->Rsi = *ContextPointers.Rsi;
1225 Context->Rdi = *ContextPointers.Rdi;
1226 Context->R12 = *ContextPointers.R12;
1227 Context->R13 = *ContextPointers.R13;
1228 Context->R14 = *ContextPointers.R14;
1229 Context->R15 = *ContextPointers.R15;
1230 }
1231 if (ContextFlags & CONTEXT_FLOATING_POINT)
1232 {
1233 Context->Xmm6 = *ContextPointers.Xmm6;
1234 Context->Xmm7 = *ContextPointers.Xmm7;
1235 Context->Xmm8 = *ContextPointers.Xmm8;
1236 Context->Xmm9 = *ContextPointers.Xmm9;
1237 Context->Xmm10 = *ContextPointers.Xmm10;
1238 Context->Xmm11 = *ContextPointers.Xmm11;
1239 Context->Xmm12 = *ContextPointers.Xmm12;
1240 Context->Xmm13 = *ContextPointers.Xmm13;
1241 Context->Xmm14 = *ContextPointers.Xmm14;
1242 Context->Xmm15 = *ContextPointers.Xmm15;
1243 }
1244}
#define CONTEXT_INTEGER
Definition: nt_native.h:1373
#define CONTEXT_FLOATING_POINT
Definition: nt_native.h:1375
static VOID RtlpCaptureNonVolatileContextPointers(_Out_ PKNONVOLATILE_CONTEXT_POINTERS NonvolatileContextPointers, _In_ ULONG64 TargetFrame)
Definition: unwind.c:1158

Referenced by KiGetTrapContextInternal().

◆ RtlLookupFunctionEntry()

PRUNTIME_FUNCTION NTAPI RtlLookupFunctionEntry ( IN DWORD64  ControlPc,
OUT PDWORD64  ImageBase,
OUT PUNWIND_HISTORY_TABLE  HistoryTable 
)

Locates the RUNTIME_FUNCTION entry corresponding to a code address. https://learn.microsoft.com/en-us/windows/win32/api/winnt/nf-winnt-rtllookupfunctionentry.

RtlLookupFunctionEntry

Todo:
Implement HistoryTable

Definition at line 124 of file unwind.c.

128{
129 PRUNTIME_FUNCTION FunctionTable, FunctionEntry;
130 ULONG TableLength;
131 ULONG IndexLo, IndexHi, IndexMid;
132
133 /* Find the corresponding table */
134 FunctionTable = RtlLookupFunctionTable(ControlPc, ImageBase, &TableLength);
135
136 /* If no table is found, try dynamic function tables */
137 if (!FunctionTable)
138 {
139 return RtlpLookupDynamicFunctionEntry(ControlPc, ImageBase, HistoryTable);
140 }
141
142 /* Use relative virtual address */
143 ControlPc -= *ImageBase;
144
145 /* Do a binary search */
146 IndexLo = 0;
147 IndexHi = TableLength;
148 while (IndexHi > IndexLo)
149 {
150 IndexMid = (IndexLo + IndexHi) / 2;
151 FunctionEntry = &FunctionTable[IndexMid];
152
153 if (ControlPc < FunctionEntry->BeginAddress)
154 {
155 /* Continue search in lower half */
156 IndexHi = IndexMid;
157 }
158 else if (ControlPc >= FunctionEntry->EndAddress)
159 {
160 /* Continue search in upper half */
161 IndexLo = IndexMid + 1;
162 }
163 else
164 {
165 /* ControlPc is within limits, return entry */
166 return FunctionEntry;
167 }
168 }
169
170 /* Nothing found, return NULL */
171 return NULL;
172}
static PRUNTIME_FUNCTION(WINAPI *pRtlLookupFunctionEntry)(ULONG_PTR
NTSYSAPI PRUNTIME_FUNCTION WINAPI RtlLookupFunctionTable(ULONG_PTR, ULONG_PTR *, ULONG *)
PRUNTIME_FUNCTION NTAPI RtlpLookupDynamicFunctionEntry(_In_ DWORD64 ControlPc, _Out_ PDWORD64 ImageBase, _In_ PUNWIND_HISTORY_TABLE HistoryTable)
Definition: dynfntbl.c:275
static WLX_DISPATCH_VERSION_1_4 FunctionTable
Definition: wlx.c:747

◆ RtlLookupFunctionTable()

PRUNTIME_FUNCTION NTAPI RtlLookupFunctionTable ( IN DWORD64  ControlPc,
OUT PDWORD64  ImageBase,
OUT PULONG  Length 
)

Locates the table of RUNTIME_FUNCTION entries for a code address.

RtlLookupFunctionTable

Parameters
ControlPcAddress of the code, for which the table should be searched.
ImageBasePointer to a DWORD64 that receives the base address of the corresponding executable image.
LengthPointer to an ULONG that receives the number of table entries present in the table.

Definition at line 82 of file unwind.c.

86{
88 ULONG Size;
89
90 /* Find corresponding file header from code address */
91 if (!RtlPcToFileHeader((PVOID)ControlPc, (PVOID*)ImageBase))
92 {
93 /* Nothing found */
94 return NULL;
95 }
96
97 /* Locate the exception directory */
99 TRUE,
101 &Size);
102
103 /* Return the number of entries */
104 *Length = Size / sizeof(RUNTIME_FUNCTION);
105
106 /* Return the address of the table */
107 return Table;
108}
#define TRUE
Definition: types.h:120
PVOID NTAPI RtlPcToFileHeader(IN PVOID PcValue, PVOID *BaseOfImage)
Definition: libsupp.c:658
#define RtlImageDirectoryEntryToData
Definition: compat.h:809
ASMGENDATA Table[]
Definition: genincdata.c:61
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION
Definition: pedump.c:262
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4539

◆ RtlpCaptureNonVolatileContextPointers()

static VOID RtlpCaptureNonVolatileContextPointers ( _Out_ PKNONVOLATILE_CONTEXT_POINTERS  NonvolatileContextPointers,
_In_ ULONG64  TargetFrame 
)
static

Definition at line 1158 of file unwind.c.

1161{
1163 PRUNTIME_FUNCTION FunctionEntry;
1164 ULONG64 ImageBase;
1165 PVOID HandlerData;
1167
1168 /* Zero out the nonvolatile context pointers */
1169 RtlZeroMemory(NonvolatileContextPointers, sizeof(*NonvolatileContextPointers));
1170
1171 /* Capture the current context */
1173
1174 do
1175 {
1176 /* Make sure nothing fishy is going on. Currently this is for kernel mode only. */
1177 ASSERT((LONG64)Context.Rip < 0);
1178 ASSERT((LONG64)Context.Rsp < 0);
1179
1180 /* Look up the function entry */
1181 FunctionEntry = RtlLookupFunctionEntry(Context.Rip, &ImageBase, NULL);
1182 if (FunctionEntry != NULL)
1183 {
1184 /* Do a virtual unwind to the caller and capture saved non-volatiles */
1185 RtlVirtualUnwind(UNW_FLAG_EHANDLER,
1186 ImageBase,
1187 Context.Rip,
1188 FunctionEntry,
1189 &Context,
1190 &HandlerData,
1192 NonvolatileContextPointers);
1193
1195 }
1196 else
1197 {
1198 Context.Rip = *(PULONG64)Context.Rsp;
1199 Context.Rsp += 8;
1200 }
1201
1202 /* Continue until we reach user mode */
1203 } while ((LONG64)Context.Rip < 0);
1204
1205 /* If the caller did the right thing, we should get past the target frame */
1206 ASSERT(EstablisherFrame >= TargetFrame);
1207}
#define ASSERT(a)
Definition: mode.c:44
unsigned __int64 ULONG64
Definition: imports.h:198
unsigned __int64 * PULONG64
Definition: imports.h:198
NTSYSAPI VOID NTAPI RtlCaptureContext(_Out_ PCONTEXT ContextRecord)
_IRQL_requires_same_ _In_ PVOID EstablisherFrame
Definition: ntbasedef.h:665
NTSYSAPI PRUNTIME_FUNCTION WINAPI RtlLookupFunctionEntry(ULONG_PTR, ULONG_PTR *, UNWIND_HISTORY_TABLE *)
PEXCEPTION_ROUTINE NTAPI RtlVirtualUnwind(_In_ ULONG HandlerType, _In_ ULONG64 ImageBase, _In_ ULONG64 ControlPc, _In_ PRUNTIME_FUNCTION FunctionEntry, _Inout_ PCONTEXT Context, _Outptr_ PVOID *HandlerData, _Out_ PULONG64 EstablisherFrame, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers)
Definition: unwind.c:478
int64_t LONG64
Definition: typedefs.h:68
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262

Referenced by RtlGetUnwindContext(), and RtlSetUnwindContext().

◆ RtlpExecuteHandlerForUnwindHandler()

EXCEPTION_DISPOSITION RtlpExecuteHandlerForUnwindHandler ( _Inout_ PEXCEPTION_RECORD  ExceptionRecord,
_In_ PVOID  EstablisherFrame,
_Inout_ PCONTEXT  ContextRecord,
_In_ PDISPATCHER_CONTEXT  DispatcherContext 
)

Definition at line 669 of file unwind.c.

674{
675 /* Get a pointer to the register home space for RtlpExecuteHandlerForUnwind */
676 PULONG64 HomeSpace = (PULONG64)EstablisherFrame + 6;
677
678 /* Get the ExceptionFlags value, which was saved in the home space */
679 ULONG ExceptionFlags = (ULONG)HomeSpace[0];
680
681 /* Get the DispatcherContext, which was saved in the home space */
682 PDISPATCHER_CONTEXT PreviousDispatcherContext = (PDISPATCHER_CONTEXT)HomeSpace[3];
683
684 /* Check if the original call to RtlpExecuteHandlerForUnwind was an unwind */
685 if (IS_UNWINDING(ExceptionFlags))
686 {
687 /* Check if the current call to this function is due to unwinding */
688 if (IS_UNWINDING(ExceptionRecord->ExceptionFlags))
689 {
690 /* We are unwinding over the call to a termination handler. This
691 could be due to an exception or longjmp. We need to make sure
692 to not run this termination handler again. To achieve that,
693 we copy the contents of the original dispatcher context back
694 over the current dispatcher context and return
695 ExceptionCollidedUnwind. RtlUnwindInternal will take the
696 original context, and continue unwing there. */
697 *DispatcherContext = *PreviousDispatcherContext;
699 }
700 }
701
702 // TODO: properly handle nested exceptions
703
705}
@ ExceptionContinueSearch
Definition: compat.h:91
@ ExceptionCollidedUnwind
Definition: compat.h:93
struct _DISPATCHER_CONTEXT * PDISPATCHER_CONTEXT
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT _In_ PVOID DispatcherContext
Definition: ntbasedef.h:667
#define IS_UNWINDING(Flag)
Definition: rtltypes.h:164

◆ RtlpIsStackPointerValid()

static __inline BOOL RtlpIsStackPointerValid ( _In_ ULONG64  StackPointer,
_In_ ULONG64  LowLimit,
_In_ ULONG64  HighLimit 
)
static

Definition at line 658 of file unwind.c.

662{
663 return (StackPointer >= LowLimit) &&
664 (StackPointer < HighLimit) &&
665 ((StackPointer & 7) == 0);
666}
_Out_ PULONG_PTR HighLimit
Definition: iofuncs.h:2885

Referenced by RtlpUnwindInternal().

◆ RtlpLookupDynamicFunctionEntry()

PRUNTIME_FUNCTION NTAPI RtlpLookupDynamicFunctionEntry ( _In_ DWORD64  ControlPc,
_Out_ PDWORD64  ImageBase,
_In_ PUNWIND_HISTORY_TABLE  HistoryTable 
)

Definition at line 275 of file dynfntbl.c.

279{
280 PLIST_ENTRY listLink;
281 PDYNAMIC_FUNCTION_TABLE dynamicTable;
282 PRUNTIME_FUNCTION functionTable, foundEntry = NULL;
284 DWORD64 ipOffset;
285 ULONG i;
286
288
289 /* Loop all tables to find the one matching ControlPc */
290 for (listLink = RtlpDynamicFunctionTableList.Flink;
291 listLink != &RtlpDynamicFunctionTableList;
292 listLink = listLink->Flink)
293 {
294 dynamicTable = CONTAINING_RECORD(listLink, DYNAMIC_FUNCTION_TABLE, ListEntry);
295
296 if ((ControlPc >= dynamicTable->MinimumAddress) &&
297 (ControlPc < dynamicTable->MaximumAddress))
298 {
299 /* Check if there is a callback */
300 callback = dynamicTable->Callback;
301 if (callback != NULL)
302 {
303 PVOID context = dynamicTable->Context;
304
305 *ImageBase = dynamicTable->BaseAddress;
307 return callback(ControlPc, context);
308 }
309
310 /* Loop all entries in the function table */
311 functionTable = dynamicTable->FunctionTable;
312 ipOffset = ControlPc - dynamicTable->BaseAddress;
313 for (i = 0; i < dynamicTable->EntryCount; i++)
314 {
315 /* Check if this entry contains the address */
316 if ((ipOffset >= functionTable[i].BeginAddress) &&
317 (ipOffset < functionTable[i].EndAddress))
318 {
319 foundEntry = &functionTable[i];
320 *ImageBase = dynamicTable->BaseAddress;
321 goto Exit;
322 }
323 }
324 }
325 }
326
327Exit:
328
330
331 return foundEntry;
332}
static __inline VOID AcquireDynamicFunctionTableLockShared()
Definition: dynfntbl.c:82
static __inline VOID ReleaseDynamicFunctionTableLockShared()
Definition: dynfntbl.c:89
LIST_ENTRY RtlpDynamicFunctionTableList
Definition: dynfntbl.c:64
static IPrintDialogCallback callback
Definition: printdlg.c:326
PRUNTIME_FUNCTION(CALLBACK * PGET_RUNTIME_FUNCTION_CALLBACK)(DWORD_PTR, PVOID)
Definition: rtlsupportapi.h:56
static void Exit(void)
Definition: sock.c:1330
PGET_RUNTIME_FUNCTION_CALLBACK Callback
Definition: dynfntbl.c:49
PRUNTIME_FUNCTION FunctionTable
Definition: dynfntbl.c:44
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
Definition: http.c:7252
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260

Referenced by RtlLookupFunctionEntry().

◆ RtlpRestoreContextInternal()

VOID RtlpRestoreContextInternal ( _In_ PCONTEXT  ContextRecord)

Referenced by RtlRestoreContext().

◆ RtlpTryToUnwindEpilog()

static __inline BOOLEAN RtlpTryToUnwindEpilog ( _Inout_ PCONTEXT  Context,
_In_ ULONG64  ControlPc,
_Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS  ContextPointers,
_In_ ULONG64  ImageBase,
_In_ PRUNTIME_FUNCTION  FunctionEntry 
)
static

Helper function that tries to unwind epilog instructions.

RtlpTryToUnwindEpilog

Returns
TRUE if we have been in an epilog and it could be unwound. FALSE if the instructions were not allowed for an epilog. https://docs.microsoft.com/en-us/cpp/build/unwind-procedure https://docs.microsoft.com/en-us/cpp/build/prolog-and-epilog
Todo:
  • Test and compare with Windows behaviour

Definition at line 304 of file unwind.c.

310{
311 CONTEXT LocalContext;
312 BYTE *InstrPtr;
313 DWORD Instr;
314 BYTE Reg, Mod;
315 ULONG64 EndAddress;
316
317 /* Make a local copy of the context */
318 LocalContext = *Context;
319
320 InstrPtr = (BYTE*)ControlPc;
321
322 /* Check if first instruction of epilog is "add rsp, x" */
323 Instr = *(DWORD*)InstrPtr;
324 if ( (Instr & 0x00fffdff) == 0x00c48148 )
325 {
326 if ( (Instr & 0x0000ff00) == 0x8300 )
327 {
328 /* This is "add rsp, 0x??" */
329 LocalContext.Rsp += Instr >> 24;
330 InstrPtr += 4;
331 }
332 else
333 {
334 /* This is "add rsp, 0x???????? */
335 LocalContext.Rsp += *(DWORD*)(InstrPtr + 3);
336 InstrPtr += 7;
337 }
338 }
339 /* Check if first instruction of epilog is "lea rsp, ..." */
340 else if ( (Instr & 0x38fffe) == 0x208d48 )
341 {
342 /* Get the register */
343 Reg = (Instr >> 16) & 0x7;
344
345 /* REX.R */
346 Reg += (Instr & 1) * 8;
347
348 LocalContext.Rsp = GetReg(&LocalContext, Reg);
349
350 /* Get addressing mode */
351 Mod = (Instr >> 22) & 0x3;
352 if (Mod == 0)
353 {
354 /* No displacement */
355 InstrPtr += 3;
356 }
357 else if (Mod == 1)
358 {
359 /* 1 byte displacement */
360 LocalContext.Rsp += (LONG)(CHAR)(Instr >> 24);
361 InstrPtr += 4;
362 }
363 else if (Mod == 2)
364 {
365 /* 4 bytes displacement */
366 LocalContext.Rsp += *(LONG*)(InstrPtr + 3);
367 InstrPtr += 7;
368 }
369 }
370
371 /* Loop the following instructions before the ret */
372 EndAddress = FunctionEntry->EndAddress + ImageBase - 1;
373 while ((DWORD64)InstrPtr < EndAddress)
374 {
375 Instr = *(DWORD*)InstrPtr;
376
377 /* Check for a simple pop */
378 if ( (Instr & 0xf8) == 0x58 )
379 {
380 /* Opcode pops a basic register from stack */
381 Reg = Instr & 0x7;
382 PopReg(&LocalContext, ContextPointers, Reg);
383 InstrPtr++;
384 continue;
385 }
386
387 /* Check for REX + pop */
388 if ( (Instr & 0xf8fb) == 0x5841 )
389 {
390 /* Opcode is pop r8 .. r15 */
391 Reg = ((Instr >> 8) & 0x7) + 8;
392 PopReg(&LocalContext, ContextPointers, Reg);
393 InstrPtr += 2;
394 continue;
395 }
396
397 /* Opcode not allowed for Epilog */
398 return FALSE;
399 }
400
401 // check for popfq
402
403 // also allow end with jmp imm, jmp [target], iretq
404
405 /* Check if we are at the ret instruction */
406 if ((DWORD64)InstrPtr != EndAddress)
407 {
408 /* If we went past the end of the function, something is broken! */
409 ASSERT((DWORD64)InstrPtr <= EndAddress);
410 return FALSE;
411 }
412
413 /* Make sure this is really a ret instruction */
414 if (*InstrPtr != 0xc3)
415 {
416 return FALSE;
417 }
418
419 /* Unwind is finished, pop new Rip from Stack */
420 LocalContext.Rip = *(DWORD64*)LocalContext.Rsp;
421 LocalContext.Rsp += sizeof(DWORD64);
422
423 *Context = LocalContext;
424 return TRUE;
425}
#define FALSE
Definition: types.h:117
unsigned long DWORD
Definition: ntddk_ex.h:95
long LONG
Definition: pedump.c:60
char CHAR
Definition: pedump.c:57
static __inline void PopReg(_Inout_ PCONTEXT Context, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ BYTE Reg)
Definition: unwind.c:247
unsigned char BYTE
Definition: xxhash.c:193

Referenced by RtlVirtualUnwind().

◆ RtlpUnwindInternal()

BOOLEAN NTAPI RtlpUnwindInternal ( _In_opt_ PVOID  TargetFrame,
_In_opt_ PVOID  TargetIp,
_In_ PEXCEPTION_RECORD  ExceptionRecord,
_In_ PVOID  ReturnValue,
_In_ PCONTEXT  ContextRecord,
_In_opt_ struct _UNWIND_HISTORY_TABLE HistoryTable,
_In_ ULONG  HandlerType 
)
Remarks
The implementation is based on the description in this blog: http://www.nynaeve.net/?p=106
Differences to the desciption:
- Instead of using 2 pointers to the unwind context and previous context,
  that are being swapped and the context copied, the unwind context is
  kept in the local context and copied back into the context passed in
  by the caller.
See also
http://www.nynaeve.net/?p=106

TODO: Handle DPC stack

TODO

TODO: Check for DPC stack

Definition at line 721 of file unwind.c.

729{
731 PEXCEPTION_ROUTINE ExceptionRoutine;
733 PRUNTIME_FUNCTION FunctionEntry;
734 ULONG_PTR StackLow, StackHigh;
735 ULONG64 ImageBase, EstablisherFrame;
736 CONTEXT UnwindContext;
737
738 /* Get the current stack limits */
739 RtlpGetStackLimits(&StackLow, &StackHigh);
740
741 /* If we have a target frame, then this is our high limit */
742 if (TargetFrame != NULL)
743 {
744 StackHigh = (ULONG64)TargetFrame + 1;
745 }
746
747 /* Copy the context */
748 UnwindContext = *ContextRecord;
749
750 /* Set up the constant fields of the dispatcher context */
751 DispatcherContext.ContextRecord =
752 (HandlerType == UNW_FLAG_UHANDLER) ? ContextRecord : &UnwindContext;
753 DispatcherContext.HistoryTable = HistoryTable;
754 DispatcherContext.TargetIp = (ULONG64)TargetIp;
755
756 /* Start looping */
757 while (TRUE)
758 {
759 if (!RtlpIsStackPointerValid(UnwindContext.Rsp, StackLow, StackHigh))
760 {
761 return FALSE;
762 }
763
764 /* Lookup the FunctionEntry for the current RIP */
765 FunctionEntry = RtlLookupFunctionEntry(UnwindContext.Rip, &ImageBase, NULL);
766 if (FunctionEntry == NULL)
767 {
768 /* No function entry, so this must be a leaf function. Pop the return address from the stack.
769 Note: this can happen after the first frame as the result of an exception */
770 UnwindContext.Rip = *(DWORD64*)UnwindContext.Rsp;
771 UnwindContext.Rsp += sizeof(DWORD64);
772
773 if (HandlerType == UNW_FLAG_UHANDLER)
774 {
775 /* Copy the context back for the next iteration */
776 *ContextRecord = UnwindContext;
777 }
778 continue;
779 }
780
781 /* Save Rip before the virtual unwind */
782 DispatcherContext.ControlPc = UnwindContext.Rip;
783
784 /* Do a virtual unwind to get the next frame */
785 ExceptionRoutine = RtlVirtualUnwind(HandlerType,
786 ImageBase,
787 UnwindContext.Rip,
788 FunctionEntry,
789 &UnwindContext,
790 &DispatcherContext.HandlerData,
792 NULL);
793
794 /* Check, if we are still within the stack boundaries */
795 if ((EstablisherFrame < StackLow) ||
796 (EstablisherFrame >= StackHigh) ||
797 (EstablisherFrame & 7))
798 {
800
801 /* If we are handling an exception, we are done here. */
802 if (HandlerType == UNW_FLAG_EHANDLER)
803 {
804 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
805 return FALSE;
806 }
807
808 __debugbreak();
810 }
811
812 /* Check if we have an exception routine */
813 if (ExceptionRoutine != NULL)
814 {
815 /* Check if this is the target frame */
816 if (EstablisherFrame == (ULONG64)TargetFrame)
817 {
818 /* Set flag to inform the language handler */
819 ExceptionRecord->ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
820 }
821
822 /* Log the exception if it's enabled */
823 RtlpCheckLogException(ExceptionRecord,
824 &UnwindContext,
826 sizeof(DispatcherContext));
827
828 /* Set up the variable fields of the dispatcher context */
829 DispatcherContext.ImageBase = ImageBase;
830 DispatcherContext.FunctionEntry = FunctionEntry;
831 DispatcherContext.LanguageHandler = ExceptionRoutine;
832 DispatcherContext.EstablisherFrame = EstablisherFrame;
833 DispatcherContext.ScopeIndex = 0;
834
835 /* Store the return value in the unwind context */
836 UnwindContext.Rax = (ULONG64)ReturnValue;
837
838 /* Loop all nested handlers */
839 do
840 {
841 /* Call the language specific handler */
846
847 /* Clear exception flags for the next iteration */
848 ExceptionRecord->ExceptionFlags &= ~(EXCEPTION_TARGET_UNWIND |
850
851 /* Check if we do exception handling */
852 if (HandlerType == UNW_FLAG_EHANDLER)
853 {
855 {
856 /* Check if it was non-continuable */
857 if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
858 {
859 __debugbreak();
861 }
862
863 /* Execution continues */
864 return TRUE;
865 }
867 {
869 __debugbreak();
870 }
871 }
872
874 {
875 /* We collided with another unwind, so we need to continue
876 "after" the handler, skipping the termination handler
877 that resulted in this unwind. The installed handler has
878 already copied the original dispatcher context, we now
879 need to copy back the original context. */
880 UnwindContext = *ContextRecord = *DispatcherContext.ContextRecord;
881
882 /* The original context was from "before" the unwind, so we
883 need to do an additional virtual unwind to restore the
884 unwind contxt. */
886 DispatcherContext.ImageBase,
887 UnwindContext.Rip,
888 DispatcherContext.FunctionEntry,
889 &UnwindContext,
890 &DispatcherContext.HandlerData,
892 NULL);
893
894 /* Restore the context pointer and establisher frame. */
895 DispatcherContext.ContextRecord = &UnwindContext;
896 EstablisherFrame = DispatcherContext.EstablisherFrame;
897
898 /* Set the exception flags to indicate that we collided
899 with an unwind and continue the handler loop, which
900 will run any additional handlers from the previous
901 unwind. */
902 ExceptionRecord->ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
903 continue;
904 }
905
906 /* This must be ExceptionContinueSearch now */
908 {
909 __debugbreak();
911 }
912 } while (ExceptionRecord->ExceptionFlags & EXCEPTION_COLLIDED_UNWIND);
913 }
914
915 /* Check, if we have left our stack (8.) */
916 if ((EstablisherFrame < StackLow) ||
917 (EstablisherFrame > StackHigh) ||
918 (EstablisherFrame & 7))
919 {
921 __debugbreak();
922
923 if (UnwindContext.Rip == ContextRecord->Rip)
924 {
926 }
927 else
928 {
929 ZwRaiseException(ExceptionRecord, ContextRecord, FALSE);
930 }
931 }
932
933 if (EstablisherFrame == (ULONG64)TargetFrame)
934 {
935 break;
936 }
937
938 if (HandlerType == UNW_FLAG_UHANDLER)
939 {
940 /* We have successfully unwound a frame. Copy the unwind context back. */
941 *ContextRecord = UnwindContext;
942 }
943 }
944
945 if (ExceptionRecord->ExceptionCode != STATUS_UNWIND_CONSOLIDATE)
946 {
947 ContextRecord->Rip = (ULONG64)TargetIp;
948 }
949
950 /* Set the return value */
952
953 /* Restore the context */
954 RtlRestoreContext(ContextRecord, ExceptionRecord);
955
956 /* Should never get here! */
957 ASSERT(FALSE);
958 return FALSE;
959}
UINT32 void void ** ReturnValue
Definition: acevents.h:216
ACPI_PHYSICAL_ADDRESS ACPI_SIZE BOOLEAN Warn UINT32 *TableIdx UINT32 ACPI_TABLE_HEADER *OutTableHeader ACPI_TABLE_HEADER **OutTable ACPI_HANDLE UINT32 ACPI_WALK_CALLBACK ACPI_WALK_CALLBACK void void **ReturnValue UINT32 ACPI_BUFFER *RetPathPtr ACPI_OBJECT_HANDLER void *Data ACPI_OBJECT_HANDLER void **Data ACPI_STRING ACPI_OBJECT_LIST ACPI_BUFFER *ReturnObjectBuffer ACPI_DEVICE_INFO **ReturnBuffer ACPI_HANDLE ACPI_HANDLE ACPI_HANDLE *OutHandle ACPI_HANDLE *OutHandle void *Context void *Context ACPI_EVENT_HANDLER Handler UINT32 UINT32 ACPI_GPE_HANDLER void *Context UINT32 HandlerType
Definition: acpixf.h:817
VOID NTAPI RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord, IN PVOID ContextData, IN ULONG Size)
Definition: libsupp.c:203
VOID NTAPI RtlpGetStackLimits(OUT PULONG_PTR LowLimit, OUT PULONG_PTR HighLimit)
Definition: libsupp.c:337
@ ExceptionNestedException
Definition: compat.h:92
@ ExceptionContinueExecution
Definition: compat.h:90
EXCEPTION_ROUTINE * PEXCEPTION_ROUTINE
Definition: compat.h:709
enum _EXCEPTION_DISPOSITION EXCEPTION_DISPOSITION
#define EXCEPTION_NONCONTINUABLE_EXCEPTION
Definition: minwinbase.h:61
_In_ ACCESS_MASK _In_ POBJECT_ATTRIBUTES _Reserved_ ULONG _In_opt_ PUNICODE_STRING _In_ ULONG _Out_opt_ PULONG Disposition
Definition: cmfuncs.h:56
NTSYSAPI NTSTATUS NTAPI ZwRaiseException(_In_ PEXCEPTION_RECORD ExceptionRecord, _In_ PCONTEXT Context, _In_ BOOLEAN SearchFrames)
DECLSPEC_NORETURN NTSYSAPI VOID NTAPI RtlRaiseStatus(_In_ NTSTATUS Status)
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT * ContextRecord
Definition: ntbasedef.h:666
#define STATUS_INVALID_DISPOSITION
Definition: ntstatus.h:368
#define STATUS_UNWIND_CONSOLIDATE
Definition: ntstatus.h:300
#define STATUS_BAD_FUNCTION_TABLE
Definition: ntstatus.h:585
#define STATUS_BAD_STACK
Definition: ntstatus.h:370
EXCEPTION_DISPOSITION NTAPI RtlpExecuteHandlerForUnwind(_Inout_ struct _EXCEPTION_RECORD *ExceptionRecord, _In_ PVOID EstablisherFrame, _Inout_ struct _CONTEXT *ContextRecord, _In_ PVOID DispatcherContext)
void __cdecl __debugbreak(void)
Definition: intrin_ppc.h:698
VOID RtlRestoreContext(_In_ PCONTEXT ContextRecord, _In_ PEXCEPTION_RECORD ExceptionRecord)
Definition: unwind.c:1288
static __inline BOOL RtlpIsStackPointerValid(_In_ ULONG64 StackPointer, _In_ ULONG64 LowLimit, _In_ ULONG64 HighLimit)
Definition: unwind.c:658
#define EXCEPTION_NONCONTINUABLE
Definition: stubs.h:23
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define EXCEPTION_STACK_INVALID
Definition: rtltypes.h:157
#define EXCEPTION_TARGET_UNWIND
Definition: rtltypes.h:159
#define EXCEPTION_COLLIDED_UNWIND
Definition: rtltypes.h:160

Referenced by RtlDispatchException(), and RtlUnwindEx().

◆ RtlRestoreContext()

VOID RtlRestoreContext ( _In_ PCONTEXT  ContextRecord,
_In_ PEXCEPTION_RECORD  ExceptionRecord 
)

Definition at line 1288 of file unwind.c.

1291{
1292 if (ExceptionRecord != NULL)
1293 {
1294 if ((ExceptionRecord->ExceptionCode == STATUS_UNWIND_CONSOLIDATE) &&
1295 (ExceptionRecord->NumberParameters >= 1))
1296 {
1297 PVOID (*Consolidate)(EXCEPTION_RECORD*) = (PVOID)ExceptionRecord->ExceptionInformation[0];
1298 // FIXME: This should be called through an asm wrapper to allow handling recursive unwinding
1299 ContextRecord->Rip = (ULONG64)Consolidate(ExceptionRecord);
1300 }
1301 else if ((ExceptionRecord->ExceptionCode == STATUS_LONGJUMP) &&
1302 (ExceptionRecord->NumberParameters >= 1))
1303 {
1304 _JUMP_BUFFER* JumpBuffer = (_JUMP_BUFFER*)ExceptionRecord->ExceptionInformation[0];
1305 ContextRecord->Rbx = JumpBuffer->Rbx;
1306 ContextRecord->Rsp = JumpBuffer->Rsp;
1307 ContextRecord->Rbp = JumpBuffer->Rbp;
1308 ContextRecord->Rsi = JumpBuffer->Rsi;
1309 ContextRecord->Rdi = JumpBuffer->Rdi;
1310 ContextRecord->R12 = JumpBuffer->R12;
1311 ContextRecord->R13 = JumpBuffer->R13;
1312 ContextRecord->R14 = JumpBuffer->R14;
1313 ContextRecord->R15 = JumpBuffer->R15;
1314 ContextRecord->Rip = JumpBuffer->Rip;
1315 ContextRecord->MxCsr = JumpBuffer->MxCsr;
1316 ContextRecord->FltSave.MxCsr = JumpBuffer->MxCsr;
1317 ContextRecord->FltSave.ControlWord = JumpBuffer->FpCsr;
1318 ContextRecord->Xmm6 = *(M128A*)&JumpBuffer->Xmm6;
1319 ContextRecord->Xmm7 = *(M128A*)&JumpBuffer->Xmm7;
1320 ContextRecord->Xmm8 = *(M128A*)&JumpBuffer->Xmm8;
1321 ContextRecord->Xmm9 = *(M128A*)&JumpBuffer->Xmm9;
1322 ContextRecord->Xmm10 = *(M128A*)&JumpBuffer->Xmm10;
1323 ContextRecord->Xmm11 = *(M128A*)&JumpBuffer->Xmm11;
1324 ContextRecord->Xmm12 = *(M128A*)&JumpBuffer->Xmm12;
1325 ContextRecord->Xmm13 = *(M128A*)&JumpBuffer->Xmm13;
1326 ContextRecord->Xmm14 = *(M128A*)&JumpBuffer->Xmm14;
1327 ContextRecord->Xmm15 = *(M128A*)&JumpBuffer->Xmm15;
1328 }
1329 }
1330
1332}
#define STATUS_LONGJUMP
Definition: ntstatus.h:297
VOID RtlpRestoreContextInternal(_In_ PCONTEXT ContextRecord)
void * PVOID
Definition: typedefs.h:50

Referenced by RtlpUnwindInternal().

◆ RtlSetUnwindContext()

VOID RtlSetUnwindContext ( _In_ PCONTEXT  Context,
_In_ DWORD64  TargetFrame 
)

Definition at line 1247 of file unwind.c.

1250{
1251 KNONVOLATILE_CONTEXT_POINTERS ContextPointers;
1252 ULONG ContextFlags = Context->ContextFlags & ~CONTEXT_AMD64;
1253
1254 /* Capture pointers to the non-volatiles up to the target frame */
1255 RtlpCaptureNonVolatileContextPointers(&ContextPointers, TargetFrame);
1256
1257 /* Copy the nonvolatiles to the captured locations */
1258 if (ContextFlags & CONTEXT_INTEGER)
1259 {
1260 *ContextPointers.Rbx = Context->Rbx;
1261 *ContextPointers.Rsi = Context->Rsi;
1262 *ContextPointers.Rdi = Context->Rdi;
1263 *ContextPointers.R12 = Context->R12;
1264 *ContextPointers.R13 = Context->R13;
1265 *ContextPointers.R14 = Context->R14;
1266 *ContextPointers.R15 = Context->R15;
1267 }
1268 if (ContextFlags & CONTEXT_FLOATING_POINT)
1269 {
1270 *ContextPointers.Xmm6 = Context->Xmm6;
1271 *ContextPointers.Xmm7 = Context->Xmm7;
1272 *ContextPointers.Xmm8 = Context->Xmm8;
1273 *ContextPointers.Xmm9 = Context->Xmm9;
1274 *ContextPointers.Xmm10 = Context->Xmm10;
1275 *ContextPointers.Xmm11 = Context->Xmm11;
1276 *ContextPointers.Xmm12 = Context->Xmm12;
1277 *ContextPointers.Xmm13 = Context->Xmm13;
1278 *ContextPointers.Xmm14 = Context->Xmm14;
1279 *ContextPointers.Xmm15 = Context->Xmm15;
1280 }
1281}

Referenced by KiSetTrapContextInternal().

◆ RtlUnwind()

VOID NTAPI RtlUnwind ( _In_opt_ PVOID TargetFrame TargetFrame  ,
_In_opt_ PVOID  TargetIp,
_In_opt_ PEXCEPTION_RECORD  ExceptionRecord,
_In_ PVOID  ReturnValue 
)

Definition at line 1006 of file unwind.c.

1011{
1013
1014 RtlUnwindEx(TargetFrame,
1015 TargetIp,
1016 ExceptionRecord,
1018 &Context,
1019 NULL);
1020}
VOID NTAPI RtlUnwindEx(_In_opt_ PVOID TargetFrame, _In_opt_ PVOID TargetIp, _In_opt_ PEXCEPTION_RECORD ExceptionRecord, _In_ PVOID ReturnValue, _In_ PCONTEXT ContextRecord, _In_opt_ struct _UNWIND_HISTORY_TABLE *HistoryTable)
Definition: unwind.c:963

◆ RtlUnwindEx()

VOID NTAPI RtlUnwindEx ( _In_opt_ PVOID  TargetFrame,
_In_opt_ PVOID  TargetIp,
_In_opt_ PEXCEPTION_RECORD  ExceptionRecord,
_In_ PVOID  ReturnValue,
_In_ PCONTEXT  ContextRecord,
_In_opt_ struct _UNWIND_HISTORY_TABLE HistoryTable 
)

Definition at line 963 of file unwind.c.

970{
971 EXCEPTION_RECORD LocalExceptionRecord;
972
973 /* Capture the current context */
975
976 /* Check if we have an exception record */
977 if (ExceptionRecord == NULL)
978 {
979 /* No exception record was passed, so set up a local one */
980 LocalExceptionRecord.ExceptionCode = STATUS_UNWIND;
981 LocalExceptionRecord.ExceptionAddress = (PVOID)ContextRecord->Rip;
982 LocalExceptionRecord.ExceptionRecord = NULL;
983 LocalExceptionRecord.NumberParameters = 0;
984 ExceptionRecord = &LocalExceptionRecord;
985 }
986
987 /* Set unwind flags */
988 ExceptionRecord->ExceptionFlags = EXCEPTION_UNWINDING;
989 if (TargetFrame == NULL)
990 {
991 ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND;
992 }
993
994 /* Call the internal function */
995 RtlpUnwindInternal(TargetFrame,
996 TargetIp,
997 ExceptionRecord,
1000 HistoryTable,
1001 UNW_FLAG_UHANDLER);
1002}
#define STATUS_UNWIND
Definition: ntstatus.h:369
BOOLEAN NTAPI RtlpUnwindInternal(_In_opt_ PVOID TargetFrame, _In_opt_ PVOID TargetIp, _In_ PEXCEPTION_RECORD ExceptionRecord, _In_ PVOID ReturnValue, _In_ PCONTEXT ContextRecord, _In_opt_ struct _UNWIND_HISTORY_TABLE *HistoryTable, _In_ ULONG HandlerType)
Definition: unwind.c:721
struct _EXCEPTION_RECORD * ExceptionRecord
Definition: compat.h:210
DWORD ExceptionCode
Definition: compat.h:208
DWORD NumberParameters
Definition: compat.h:212
PVOID ExceptionAddress
Definition: compat.h:211
#define EXCEPTION_EXIT_UNWIND
Definition: rtltypes.h:156
#define EXCEPTION_UNWINDING
Definition: rtltypes.h:155

Referenced by RtlUnwind().

◆ RtlVirtualUnwind()

PEXCEPTION_ROUTINE NTAPI RtlVirtualUnwind ( _In_ ULONG  HandlerType,
_In_ ULONG64  ImageBase,
_In_ ULONG64  ControlPc,
_In_ PRUNTIME_FUNCTION  FunctionEntry,
_Inout_ PCONTEXT  Context,
_Outptr_ PVOID HandlerData,
_Out_ PULONG64  EstablisherFrame,
_Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS  ContextPointers 
)

Definition at line 478 of file unwind.c.

487{
488 PUNWIND_INFO UnwindInfo;
489 ULONG_PTR ControlRva, CodeOffset;
490 ULONG i, Offset;
491 UNWIND_CODE UnwindCode;
492 BYTE Reg;
493 PULONG LanguageHandler;
494
495 /* Get relative virtual address */
496 ControlRva = ControlPc - ImageBase;
497
498 /* Sanity checks */
499 if ( (ControlRva < FunctionEntry->BeginAddress) ||
500 (ControlRva >= FunctionEntry->EndAddress) )
501 {
502 return NULL;
503 }
504
505 /* Get a pointer to the unwind info */
506 UnwindInfo = RVA(ImageBase, FunctionEntry->UnwindData);
507
508 /* The language specific handler data follows the unwind info */
509 LanguageHandler = ALIGN_UP_POINTER_BY(&UnwindInfo->UnwindCode[UnwindInfo->CountOfCodes], sizeof(ULONG));
510
511 /* Calculate relative offset to function start */
512 CodeOffset = ControlRva - FunctionEntry->BeginAddress;
513
514 *EstablisherFrame = GetEstablisherFrame(Context, UnwindInfo, CodeOffset);
515
516 /* Check if we are in the function epilog and try to finish it */
517 if ((CodeOffset > UnwindInfo->SizeOfProlog) && (UnwindInfo->CountOfCodes > 0))
518 {
519 if (RtlpTryToUnwindEpilog(Context, ControlPc, ContextPointers, ImageBase, FunctionEntry))
520 {
521 /* There's no exception routine */
522 return NULL;
523 }
524 }
525
526 /* Skip all Ops with an offset greater than the current Offset */
527 i = 0;
528 while ((i < UnwindInfo->CountOfCodes) &&
529 (UnwindInfo->UnwindCode[i].CodeOffset > CodeOffset))
530 {
531 i += UnwindOpSlots(UnwindInfo->UnwindCode[i]);
532 }
533
534RepeatChainedInfo:
535
536 /* Process the remaining unwind ops */
537 while (i < UnwindInfo->CountOfCodes)
538 {
539 UnwindCode = UnwindInfo->UnwindCode[i];
540 switch (UnwindCode.UnwindOp)
541 {
542 case UWOP_PUSH_NONVOL:
543 Reg = UnwindCode.OpInfo;
544 PopReg(Context, ContextPointers, Reg);
545 i++;
546 break;
547
548 case UWOP_ALLOC_LARGE:
549 if (UnwindCode.OpInfo)
550 {
551 Offset = *(ULONG*)(&UnwindInfo->UnwindCode[i+1]);
552 Context->Rsp += Offset;
553 i += 3;
554 }
555 else
556 {
557 Offset = UnwindInfo->UnwindCode[i+1].FrameOffset;
558 Context->Rsp += Offset * 8;
559 i += 2;
560 }
561 break;
562
563 case UWOP_ALLOC_SMALL:
564 Context->Rsp += (UnwindCode.OpInfo + 1) * 8;
565 i++;
566 break;
567
568 case UWOP_SET_FPREG:
569 Reg = UnwindInfo->FrameRegister;
570 Context->Rsp = GetReg(Context, Reg) - UnwindInfo->FrameOffset * 16;
571 i++;
572 break;
573
574 case UWOP_SAVE_NONVOL:
575 Reg = UnwindCode.OpInfo;
576 Offset = UnwindInfo->UnwindCode[i + 1].FrameOffset;
577 /* The slot stores offset / 8; adding it to a DWORD64* scales it back to bytes.
578 * See https://github.com/dotnet/runtime/blob/421be955e4b70cddf583b10f5ad99814b713fb87/src/coreclr/unwinder/amd64/unwinder.cpp#L831 */
579 SetRegFromStackValue(Context, ContextPointers, Reg, (DWORD64*)Context->Rsp + Offset);
580 i += 2;
581 break;
582
584 Reg = UnwindCode.OpInfo;
585 Offset = *(ULONG*)(&UnwindInfo->UnwindCode[i + 1]);
586 SetRegFromStackValue(Context, ContextPointers, Reg, (PDWORD64)(Context->Rsp + Offset));
587 i += 3;
588 break;
589
590 case UWOP_EPILOG:
591 i += 2;
592 break;
593
594 case UWOP_SPARE_CODE:
595 ASSERT(FALSE);
596 i += 3;
597 break;
598
599 case UWOP_SAVE_XMM128:
600 Reg = UnwindCode.OpInfo;
601 Offset = UnwindInfo->UnwindCode[i + 1].FrameOffset;
602 /* The slot stores offset / 16; adding it to an M128A* scales it back to bytes.
603 * See https://github.com/dotnet/runtime/blob/421be955e4b70cddf583b10f5ad99814b713fb87/src/coreclr/unwinder/amd64/unwinder.cpp#L890 */
604 SetXmmRegFromStackValue(Context, ContextPointers, Reg, (M128A*)Context->Rsp + Offset);
605 i += 2;
606 break;
607
609 Reg = UnwindCode.OpInfo;
610 Offset = *(ULONG*)(&UnwindInfo->UnwindCode[i + 1]);
611 SetXmmRegFromStackValue(Context, ContextPointers, Reg, (M128A*)(Context->Rsp + Offset));
612 i += 3;
613 break;
614
616 /* OpInfo is 1, when an error code was pushed, otherwise 0. */
617 Context->Rsp += UnwindCode.OpInfo * sizeof(DWORD64);
618
619 /* Now pop the MACHINE_FRAME (RIP/RSP only. And yes, "magic numbers", deal with it) */
620 Context->Rip = *(PDWORD64)(Context->Rsp + 0x00);
621 Context->Rsp = *(PDWORD64)(Context->Rsp + 0x18);
622 ASSERT((i + 1) == UnwindInfo->CountOfCodes);
623 goto Exit;
624 }
625 }
626
627 /* Check for chained info */
628 if (UnwindInfo->Flags & UNW_FLAG_CHAININFO)
629 {
630 /* See https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64?view=msvc-160#chained-unwind-info-structures */
631 FunctionEntry = (PRUNTIME_FUNCTION)&(UnwindInfo->UnwindCode[(UnwindInfo->CountOfCodes + 1) & ~1]);
632 UnwindInfo = RVA(ImageBase, FunctionEntry->UnwindData);
633 i = 0;
634 goto RepeatChainedInfo;
635 }
636
637 /* Unwind is finished, pop new Rip from Stack */
638 if (Context->Rsp != 0)
639 {
640 Context->Rip = *(DWORD64*)Context->Rsp;
641 Context->Rsp += sizeof(DWORD64);
642 }
643
644Exit:
645
646 /* Check if we have a handler and return it */
647 if (UnwindInfo->Flags & (HandlerType & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER)))
648 {
649 *HandlerData = (LanguageHandler + 1);
650 return RVA(ImageBase, *LanguageHandler);
651 }
652
653 return NULL;
654}
#define RVA(m, b)
Definition: freeldr.h:35
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
#define UWOP_EPILOG
Definition: unwind.c:29
#define UWOP_SAVE_NONVOL
Definition: unwind.c:23
#define UWOP_SPARE_CODE
Definition: unwind.c:30
static ULONG64 GetEstablisherFrame(_In_ PCONTEXT Context, _In_ PUNWIND_INFO UnwindInfo, _In_ ULONG_PTR CodeOffset)
Definition: unwind.c:433
#define UWOP_SAVE_NONVOL_FAR
Definition: unwind.c:24
#define UWOP_PUSH_MACHFRAME
Definition: unwind.c:34
#define UWOP_ALLOC_LARGE
Definition: unwind.c:20
static __inline BOOLEAN RtlpTryToUnwindEpilog(_Inout_ PCONTEXT Context, _In_ ULONG64 ControlPc, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ ULONG64 ImageBase, _In_ PRUNTIME_FUNCTION FunctionEntry)
Helper function that tries to unwind epilog instructions.
Definition: unwind.c:304
#define UWOP_ALLOC_SMALL
Definition: unwind.c:21
#define UWOP_SAVE_XMM128
Definition: unwind.c:32
static __inline void SetXmmRegFromStackValue(_Out_ PCONTEXT Context, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ BYTE Reg, _In_ M128A *ValuePointer)
Definition: unwind.c:270
#define UWOP_SAVE_XMM128_FAR
Definition: unwind.c:33
#define UWOP_PUSH_NONVOL
Definition: unwind.c:19
BYTE CountOfCodes
Definition: cpu_x86_64.c:65
BYTE FrameOffset
Definition: cpu_x86_64.c:67
UNWIND_CODE UnwindCode[1]
Definition: cpu_x86_64.c:68
BYTE SizeOfProlog
Definition: cpu_x86_64.c:64
BYTE FrameRegister
Definition: cpu_x86_64.c:66
uint32_t * PULONG
Definition: typedefs.h:59
#define ALIGN_UP_POINTER_BY(ptr, align)
Definition: umtypes.h:85
BYTE UnwindOp
Definition: cpu_x86_64.c:54
BYTE CodeOffset
Definition: cpu_x86_64.c:53
USHORT FrameOffset
Definition: cpu_x86_64.c:57

◆ RtlWalkFrameChain()

ULONG NTAPI RtlWalkFrameChain ( OUT PVOID Callers,
IN ULONG  Count,
IN ULONG  Flags 
)

Definition at line 1024 of file unwind.c.

1027{
1029 ULONG64 ControlPc, ImageBase, EstablisherFrame;
1030 ULONG64 StackLow, StackHigh;
1031 PVOID HandlerData;
1032 ULONG i, FramesToSkip;
1033 PRUNTIME_FUNCTION FunctionEntry;
1034 MODE CurrentMode = RtlpGetMode();
1035
1036 DPRINT("Enter RtlWalkFrameChain\n");
1037
1038 /* The upper bits in Flags define how many frames to skip */
1039 FramesToSkip = Flags >> 8;
1040
1041 /* Capture the current Context */
1043 ControlPc = Context.Rip;
1044
1045 /* Get the stack limits */
1046 RtlpGetStackLimits(&StackLow, &StackHigh);
1047
1048 _SEH2_TRY
1049 {
1050 /* Loop the frames */
1051 for (i = 0; i < FramesToSkip + Count; i++)
1052 {
1053 /* Lookup the FunctionEntry for the current ControlPc */
1054 FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);
1055
1056 /* Is this a leaf function? */
1057 if (!FunctionEntry)
1058 {
1059 Context.Rip = *(DWORD64*)Context.Rsp;
1060 Context.Rsp += sizeof(DWORD64);
1061 DPRINT("leaf funtion, new Rip = %p, new Rsp = %p\n", (PVOID)Context.Rip, (PVOID)Context.Rsp);
1062 }
1063 else
1064 {
1066 ImageBase,
1067 ControlPc,
1068 FunctionEntry,
1069 &Context,
1070 &HandlerData,
1072 NULL);
1073 DPRINT("normal funtion, new Rip = %p, new Rsp = %p\n", (PVOID)Context.Rip, (PVOID)Context.Rsp);
1074 }
1075
1076 /* Check if we are in kernel mode */
1077 if (CurrentMode == KernelMode)
1078 {
1079 /* Check if we left the kernel range */
1080 if (Context.Rip < 0xFFFF800000000000ULL)
1081 {
1082 /* Bail out, unless user mode was requested */
1083 if ((Flags & 1) == 0)
1084 {
1085 break;
1086 }
1087
1088 /* We are in user mode now, get UM stack bounds */
1089 CurrentMode = UserMode;
1090 StackLow = (ULONG64)NtCurrentTeb()->NtTib.StackLimit;
1091 StackHigh = (ULONG64)NtCurrentTeb()->NtTib.StackBase;
1092 }
1093 }
1094
1095 /* Check (again) if we are in user mode now */
1096 if (CurrentMode == UserMode)
1097 {
1098 /* Check if we left the user range */
1099 if ((Context.Rip < 0x10000) ||
1100 (Context.Rip > 0x000007FFFFFEFFFFULL))
1101 {
1102 break;
1103 }
1104 }
1105
1106 /* Check, if we have left our stack */
1107 if ((Context.Rsp <= StackLow) || (Context.Rsp >= StackHigh))
1108 {
1109 break;
1110 }
1111
1112 /* Continue with new Rip */
1113 ControlPc = Context.Rip;
1114
1115 /* Save value, if we are past the frames to skip */
1116 if (i >= FramesToSkip)
1117 {
1118 Callers[i - FramesToSkip] = (PVOID)ControlPc;
1119 }
1120 }
1121 }
1123 {
1124 DPRINT1("Exception while getting callers!\n");
1125 i = 0;
1126 }
1127 _SEH2_END;
1128
1129 DPRINT("RtlWalkFrameChain returns %ld\n", i);
1130 return i;
1131}
#define DPRINT1
Definition: precomp.h:8
KPROCESSOR_MODE NTAPI RtlpGetMode(VOID)
Definition: libsupp.c:55
#define UNW_FLAG_NHANDLER
Definition: gs_support.c:32
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
#define NtCurrentTeb
#define KernelMode
Definition: asm.h:38
#define UserMode
Definition: asm.h:39
int Count
Definition: noreturn.cpp:7
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:104
#define _SEH2_END
Definition: pseh2_64.h:194
#define _SEH2_TRY
Definition: pseh2_64.h:93
#define DPRINT
Definition: sndvol32.h:73
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
enum _MODE MODE

Referenced by RtlGetCallersAddress().

◆ SetReg()

static __inline void SetReg ( _Inout_ PCONTEXT  Context,
_In_ BYTE  Reg,
_In_ DWORD64  Value 
)
static

Definition at line 210 of file unwind.c.

214{
215 ((DWORD64*)(&Context->Rax))[Reg] = Value;
216}
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413

Referenced by SetRegFromStackValue().

◆ SetRegFromStackValue()

static __inline void SetRegFromStackValue ( _Inout_ PCONTEXT  Context,
_Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS  ContextPointers,
_In_ BYTE  Reg,
_In_ PDWORD64  ValuePointer 
)
static

Definition at line 221 of file unwind.c.

226{
227 SetReg(Context, Reg, *ValuePointer);
228 if (ContextPointers != NULL)
229 {
230 ContextPointers->IntegerContext[Reg] = ValuePointer;
231 }
232}
static __inline void SetReg(_Inout_ PCONTEXT Context, _In_ BYTE Reg, _In_ DWORD64 Value)
Definition: unwind.c:210

Referenced by PopReg(), and RtlVirtualUnwind().

◆ SetXmmReg()

static __inline void SetXmmReg ( _Inout_ PCONTEXT  Context,
_In_ BYTE  Reg,
_In_ M128A  Value 
)
static

Definition at line 259 of file unwind.c.

263{
264 ((M128A*)(&Context->Xmm0))[Reg] = Value;
265}

Referenced by SetXmmRegFromStackValue().

◆ SetXmmRegFromStackValue()

static __inline void SetXmmRegFromStackValue ( _Out_ PCONTEXT  Context,
_Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS  ContextPointers,
_In_ BYTE  Reg,
_In_ M128A ValuePointer 
)
static

Definition at line 270 of file unwind.c.

275{
276 SetXmmReg(Context, Reg, *ValuePointer);
277 if (ContextPointers != NULL)
278 {
279 ContextPointers->FloatingContext[Reg] = ValuePointer;
280 }
281}
static __inline void SetXmmReg(_Inout_ PCONTEXT Context, _In_ BYTE Reg, _In_ M128A Value)
Definition: unwind.c:259

Referenced by RtlVirtualUnwind().

◆ UnwindOpSlots()

static __inline ULONG UnwindOpSlots ( _In_ UNWIND_CODE  UnwindCode)
static

Definition at line 177 of file unwind.c.

179{
180 static const UCHAR UnwindOpExtraSlotTable[] =
181 {
182 0, // UWOP_PUSH_NONVOL
183 1, // UWOP_ALLOC_LARGE (or 3, special cased in lookup code)
184 0, // UWOP_ALLOC_SMALL
185 0, // UWOP_SET_FPREG
186 1, // UWOP_SAVE_NONVOL
187 2, // UWOP_SAVE_NONVOL_FAR
188 1, // UWOP_EPILOG // previously UWOP_SAVE_XMM
189 2, // UWOP_SPARE_CODE // previously UWOP_SAVE_XMM_FAR
190 1, // UWOP_SAVE_XMM128
191 2, // UWOP_SAVE_XMM128_FAR
192 0, // UWOP_PUSH_MACHFRAME
193 2, // UWOP_SET_FPREG_LARGE
194 };
195
196 if ((UnwindCode.UnwindOp == UWOP_ALLOC_LARGE) &&
197 (UnwindCode.OpInfo != 0))
198 {
199 return 3;
200 }
201 else
202 {
203 return UnwindOpExtraSlotTable[UnwindCode.UnwindOp] + 1;
204 }
205}
unsigned char UCHAR
Definition: typedefs.h:53

Referenced by GetEstablisherFrame(), and RtlVirtualUnwind().