ReactOS 0.4.15-dev-6680-g8c76870
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. http://msdn.microsoft.com/en-us/library/ms680597(VS.85).aspx.
 
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)
 
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 RtlSetUnwindContext (_In_ PCONTEXT Context, _In_ DWORD64 TargetFrame)
 

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 434 of file unwind.c.

438{
439 ULONG i;
440
441 /* Check if we have a frame register */
442 if (UnwindInfo->FrameRegister == 0)
443 {
444 /* No frame register means we use Rsp */
445 return Context->Rsp;
446 }
447
448 if ((CodeOffset >= UnwindInfo->SizeOfProlog) ||
449 ((UnwindInfo->Flags & UNW_FLAG_CHAININFO) != 0))
450 {
451 return GetReg(Context, UnwindInfo->FrameRegister) -
452 UnwindInfo->FrameOffset * 16;
453 }
454
455 /* Loop all unwind ops */
456 for (i = 0;
457 i < UnwindInfo->CountOfCodes;
458 i += UnwindOpSlots(UnwindInfo->UnwindCode[i]))
459 {
460 /* Skip codes past our code offset */
461 if (UnwindInfo->UnwindCode[i].CodeOffset > CodeOffset)
462 {
463 continue;
464 }
465
466 /* Check for SET_FPREG */
467 if (UnwindInfo->UnwindCode[i].UnwindOp == UWOP_SET_FPREG)
468 {
469 return GetReg(Context, UnwindInfo->FrameRegister) -
470 UnwindInfo->FrameOffset * 16;
471 }
472 }
473
474 return Context->Rsp;
475}
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
@ UNW_FLAG_CHAININFO
Definition: rsym64.h:110
uint32_t ULONG
Definition: typedefs.h:59
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

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:925

◆ 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}
uint64_t * PDWORD64
Definition: typedefs.h:67
static __inline void SetRegFromStackValue(_Inout_ PCONTEXT Context, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ BYTE Reg, _In_ PDWORD64 ValuePointer)
Definition: unwind.c:221

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 1039 of file unwind.c.

1042{
1043 PVOID Callers[4];
1044 ULONG Number;
1045
1046 /* Get callers:
1047 * RtlWalkFrameChain -> RtlGetCallersAddress -> x -> y */
1048 Number = RtlWalkFrameChain(Callers, 4, 0);
1049
1050 *CallersAddress = (Number >= 3) ? Callers[2] : NULL;
1051 *CallersCaller = (Number == 4) ? Callers[3] : NULL;
1052
1053 return;
1054}
#define NULL
Definition: types.h:112
_In_opt_ PENTER_STATE_SYSTEM_HANDLER _In_opt_ PVOID _In_ LONG _In_opt_ LONG volatile * Number
Definition: ntpoapi.h:207
ULONG NTAPI RtlWalkFrameChain(OUT PVOID *Callers, IN ULONG Count, IN ULONG Flags)
Definition: unwind.c:931

◆ 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. http://msdn.microsoft.com/en-us/library/ms680597(VS.85).aspx.

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}
PRUNTIME_FUNCTION NTAPI RtlpLookupDynamicFunctionEntry(_In_ DWORD64 ControlPc, _Out_ PDWORD64 ImageBase, _In_ PUNWIND_HISTORY_TABLE HistoryTable)
Definition: dynfntbl.c:271
PRUNTIME_FUNCTION NTAPI RtlLookupFunctionTable(IN DWORD64 ControlPc, OUT PDWORD64 ImageBase, OUT PULONG Length)
Locates the table of RUNTIME_FUNCTION entries for a code address.
Definition: unwind.c:82
static WLX_DISPATCH_VERSION_1_4 FunctionTable
Definition: wlx.c:722

Referenced by RtlpCaptureNonVolatileContextPointers(), RtlpUnwindInternal(), and RtlWalkFrameChain().

◆ 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:659
#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
struct _RUNTIME_FUNCTION RUNTIME_FUNCTION
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4533

Referenced by RtlLookupFunctionEntry().

◆ RtlpCaptureNonVolatileContextPointers()

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

Definition at line 1058 of file unwind.c.

1061{
1063 PRUNTIME_FUNCTION FunctionEntry;
1064 ULONG64 ImageBase;
1065 PVOID HandlerData;
1067
1068 /* Zero out the nonvolatile context pointers */
1069 RtlZeroMemory(NonvolatileContextPointers, sizeof(*NonvolatileContextPointers));
1070
1071 /* Capture the current context */
1073
1074 do
1075 {
1076 /* Make sure nothing fishy is going on. Currently this is for kernel mode only. */
1077 ASSERT((LONG64)Context.Rip < 0);
1078 ASSERT((LONG64)Context.Rsp < 0);
1079
1080 /* Look up the function entry */
1081 FunctionEntry = RtlLookupFunctionEntry(Context.Rip, &ImageBase, NULL);
1082 if (FunctionEntry != NULL)
1083 {
1084 /* Do a virtual unwind to the caller and capture saved non-volatiles */
1086 ImageBase,
1087 Context.Rip,
1088 FunctionEntry,
1089 &Context,
1090 &HandlerData,
1092 NonvolatileContextPointers);
1093
1095 }
1096 else
1097 {
1098 Context.Rip = *(PULONG64)Context.Rsp;
1099 Context.Rsp += 8;
1100 }
1101
1102 /* Continue until we reach user mode */
1103 } while ((LONG64)Context.Rip < 0);
1104
1105 /* If the caller did the right thing, we should get past the target frame */
1106 ASSERT(EstablisherFrame >= TargetFrame);
1107}
#define ASSERT(a)
Definition: mode.c:44
unsigned __int64 * PULONG64
Definition: imports.h:198
unsigned __int64 ULONG64
Definition: imports.h:198
NTSYSAPI VOID NTAPI RtlCaptureContext(_Out_ PCONTEXT ContextRecord)
_IRQL_requires_same_ _In_ PVOID EstablisherFrame
Definition: ntbasedef.h:653
@ UNW_FLAG_EHANDLER
Definition: rsym64.h:108
int64_t LONG64
Definition: typedefs.h:68
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
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:479
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. http://msdn.microsoft....
Definition: unwind.c:124

Referenced by RtlSetUnwindContext().

◆ RtlpLookupDynamicFunctionEntry()

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

Definition at line 271 of file dynfntbl.c.

275{
276 PLIST_ENTRY listLink;
277 PDYNAMIC_FUNCTION_TABLE dynamicTable;
278 PRUNTIME_FUNCTION functionTable, foundEntry = NULL;
279 PGET_RUNTIME_FUNCTION_CALLBACK callback;
280 ULONG i;
281
283
284 /* Loop all tables to find the one matching ControlPc */
285 for (listLink = RtlpDynamicFunctionTableList.Flink;
286 listLink != &RtlpDynamicFunctionTableList;
287 listLink = listLink->Flink)
288 {
289 dynamicTable = CONTAINING_RECORD(listLink, DYNAMIC_FUNCTION_TABLE, ListEntry);
290
291 if ((ControlPc >= dynamicTable->MinimumAddress) &&
292 (ControlPc < dynamicTable->MaximumAddress))
293 {
294 /* Check if there is a callback */
295 callback = dynamicTable->Callback;
296 if (callback != NULL)
297 {
298 PVOID context = dynamicTable->Context;
299
300 *ImageBase = dynamicTable->BaseAddress;
302 return callback(ControlPc, context);
303 }
304
305 /* Loop all entries in the function table */
306 functionTable = dynamicTable->FunctionTable;
307 for (i = 0; i < dynamicTable->EntryCount; i++)
308 {
309 /* Check if this entry contains the address */
310 if ((ControlPc >= functionTable[i].BeginAddress) &&
311 (ControlPc < functionTable[i].EndAddress))
312 {
313 foundEntry = &functionTable[i];
314 *ImageBase = dynamicTable->BaseAddress;
315 goto Exit;
316 }
317 }
318 }
319 }
320
321Exit:
322
324
325 return foundEntry;
326}
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
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().

◆ 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 adressing 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 ASSERT(FALSE);
417 return FALSE;
418 }
419
420 /* Unwind is finished, pop new Rip from Stack */
421 LocalContext.Rip = *(DWORD64*)LocalContext.Rsp;
422 LocalContext.Rsp += sizeof(DWORD64);
423
424 *Context = LocalContext;
425 return TRUE;
426}
#define FALSE
Definition: types.h:117
unsigned long DWORD
Definition: ntddk_ex.h:95
long LONG
Definition: pedump.c:60
static __inline void PopReg(_Inout_ PCONTEXT Context, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ BYTE Reg)
Definition: unwind.c:247
char CHAR
Definition: xmlstorage.h:175
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: call RtlpExecuteHandlerForUnwind instead

TODO

TODO

TODO: Check for DPC stack

Definition at line 666 of file unwind.c.

674{
676 PEXCEPTION_ROUTINE ExceptionRoutine;
678 PRUNTIME_FUNCTION FunctionEntry;
679 ULONG_PTR StackLow, StackHigh;
680 ULONG64 ImageBase, EstablisherFrame;
681 CONTEXT UnwindContext;
682
683 /* Get the current stack limits and registration frame */
684 RtlpGetStackLimits(&StackLow, &StackHigh);
685
686 /* If we have a target frame, then this is our high limit */
687 if (TargetFrame != NULL)
688 {
689 StackHigh = (ULONG64)TargetFrame + 1;
690 }
691
692 /* Copy the context */
693 UnwindContext = *ContextRecord;
694
695 /* Set up the constant fields of the dispatcher context */
696 DispatcherContext.ContextRecord = &UnwindContext;
697 DispatcherContext.HistoryTable = HistoryTable;
698 DispatcherContext.TargetIp = (ULONG64)TargetIp;
699
700 /* Start looping */
701 while (TRUE)
702 {
703 /* Lookup the FunctionEntry for the current RIP */
704 FunctionEntry = RtlLookupFunctionEntry(UnwindContext.Rip, &ImageBase, NULL);
705 if (FunctionEntry == NULL)
706 {
707 /* No function entry, so this must be a leaf function. Pop the return address from the stack.
708 Note: this can happen after the first frame as the result of an exception */
709 UnwindContext.Rip = *(DWORD64*)UnwindContext.Rsp;
710 UnwindContext.Rsp += sizeof(DWORD64);
711
712 /* Copy the context back for the next iteration */
713 *ContextRecord = UnwindContext;
714 continue;
715 }
716
717 /* Save Rip before the virtual unwind */
718 DispatcherContext.ControlPc = UnwindContext.Rip;
719
720 /* Do a virtual unwind to get the next frame */
721 ExceptionRoutine = RtlVirtualUnwind(HandlerType,
722 ImageBase,
723 UnwindContext.Rip,
724 FunctionEntry,
725 &UnwindContext,
726 &DispatcherContext.HandlerData,
728 NULL);
729
730 /* Check, if we are still within the stack boundaries */
731 if ((EstablisherFrame < StackLow) ||
732 (EstablisherFrame >= StackHigh) ||
733 (EstablisherFrame & 7))
734 {
736
737 /* If we are handling an exception, we are done here. */
739 {
740 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
741 return FALSE;
742 }
743
744 __debugbreak();
746 }
747
748 /* Check if we have an exception routine */
749 if (ExceptionRoutine != NULL)
750 {
751 /* Check if this is the target frame */
752 if (EstablisherFrame == (ULONG64)TargetFrame)
753 {
754 /* Set flag to inform the language handler */
755 ExceptionRecord->ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
756 }
757
758 /* Log the exception if it's enabled */
759 RtlpCheckLogException(ExceptionRecord,
762 sizeof(DispatcherContext));
763
764 /* Set up the variable fields of the dispatcher context */
765 DispatcherContext.ImageBase = ImageBase;
766 DispatcherContext.FunctionEntry = FunctionEntry;
767 DispatcherContext.LanguageHandler = ExceptionRoutine;
768 DispatcherContext.EstablisherFrame = EstablisherFrame;
769 DispatcherContext.ScopeIndex = 0;
770
771 /* Store the return value in the unwind context */
772 UnwindContext.Rax = (ULONG64)ReturnValue;
773
774 /* Loop all nested handlers */
775 do
776 {
778 /* Call the language specific handler */
779 Disposition = ExceptionRoutine(ExceptionRecord,
783
784 /* Clear exception flags for the next iteration */
785 ExceptionRecord->ExceptionFlags &= ~(EXCEPTION_TARGET_UNWIND |
787
788 /* Check if we do exception handling */
790 {
792 {
793 /* Check if it was non-continuable */
794 if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
795 {
796 __debugbreak();
798 }
799
800 /* Execution continues */
801 return TRUE;
802 }
804 {
806 __debugbreak();
807 }
808 }
809
811 {
813 __debugbreak();
814 }
815
816 /* This must be ExceptionContinueSearch now */
818 {
819 __debugbreak();
821 }
822 } while (ExceptionRecord->ExceptionFlags & EXCEPTION_COLLIDED_UNWIND);
823 }
824
825 /* Check, if we have left our stack (8.) */
826 if ((EstablisherFrame < StackLow) ||
827 (EstablisherFrame > StackHigh) ||
828 (EstablisherFrame & 7))
829 {
831 __debugbreak();
832
833 if (UnwindContext.Rip == ContextRecord->Rip)
834 {
836 }
837 else
838 {
839 ZwRaiseException(ExceptionRecord, ContextRecord, FALSE);
840 }
841 }
842
843 if (EstablisherFrame == (ULONG64)TargetFrame)
844 {
845 break;
846 }
847
848 /* We have successfully unwound a frame. Copy the unwind context back. */
849 *ContextRecord = UnwindContext;
850 }
851
852 if (ExceptionRecord->ExceptionCode != STATUS_UNWIND_CONSOLIDATE)
853 {
854 ContextRecord->Rip = (ULONG64)TargetIp;
855 }
856
857 /* Set the return value */
859
860 /* Restore the context */
861 RtlRestoreContext(ContextRecord, ExceptionRecord);
862
863 /* Should never get here! */
864 ASSERT(FALSE);
865 return FALSE;
866}
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:201
@ ExceptionContinueSearch
Definition: compat.h:91
@ ExceptionCollidedUnwind
Definition: compat.h:93
@ ExceptionNestedException
Definition: compat.h:92
@ ExceptionContinueExecution
Definition: compat.h:90
EXCEPTION_ROUTINE * PEXCEPTION_ROUTINE
Definition: compat.h:709
enum _EXCEPTION_DISPOSITION EXCEPTION_DISPOSITION
void __cdecl __debugbreak(void)
Definition: intrin_ppc.h:698
_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:654
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT _In_ PVOID DispatcherContext
Definition: ntbasedef.h:655
VOID NTAPI RtlpGetStackLimits(PULONG_PTR StackBase, PULONG_PTR StackLimit)
#define STATUS_INVALID_DISPOSITION
Definition: ntstatus.h:275
#define STATUS_UNWIND_CONSOLIDATE
Definition: ntstatus.h:220
#define STATUS_BAD_FUNCTION_TABLE
Definition: ntstatus.h:491
#define STATUS_BAD_STACK
Definition: ntstatus.h:277
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define EXCEPTION_NONCONTINUABLE_EXCEPTION
Definition: winbase.h:328
#define EXCEPTION_NONCONTINUABLE
Definition: rtltypes.h:154
#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().

◆ RtlSetUnwindContext()

VOID RtlSetUnwindContext ( _In_ PCONTEXT  Context,
_In_ DWORD64  TargetFrame 
)

Definition at line 1110 of file unwind.c.

1113{
1114 KNONVOLATILE_CONTEXT_POINTERS ContextPointers;
1115
1116 /* Capture pointers to the non-volatiles up to the target frame */
1117 RtlpCaptureNonVolatileContextPointers(&ContextPointers, TargetFrame);
1118
1119 /* Copy the nonvolatiles to the captured locations */
1120 *ContextPointers.R12 = Context->R12;
1121 *ContextPointers.R13 = Context->R13;
1122 *ContextPointers.R14 = Context->R14;
1123 *ContextPointers.R15 = Context->R15;
1124 *ContextPointers.Xmm6 = Context->Xmm6;
1125 *ContextPointers.Xmm7 = Context->Xmm7;
1126 *ContextPointers.Xmm8 = Context->Xmm8;
1127 *ContextPointers.Xmm9 = Context->Xmm9;
1128 *ContextPointers.Xmm10 = Context->Xmm10;
1129 *ContextPointers.Xmm11 = Context->Xmm11;
1130 *ContextPointers.Xmm12 = Context->Xmm12;
1131 *ContextPointers.Xmm13 = Context->Xmm13;
1132 *ContextPointers.Xmm14 = Context->Xmm14;
1133 *ContextPointers.Xmm15 = Context->Xmm15;
1134}
static VOID RtlpCaptureNonVolatileContextPointers(_Out_ PKNONVOLATILE_CONTEXT_POINTERS NonvolatileContextPointers, _In_ ULONG64 TargetFrame)
Definition: unwind.c:1058

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 913 of file unwind.c.

918{
920
921 RtlUnwindEx(TargetFrame,
922 TargetIp,
923 ExceptionRecord,
925 &Context,
926 NULL);
927}
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:870

Referenced by _local_unwind(), and _SEH2GlobalUnwind().

◆ 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 870 of file unwind.c.

877{
878 EXCEPTION_RECORD LocalExceptionRecord;
879
880 /* Capture the current context */
882
883 /* Check if we have an exception record */
884 if (ExceptionRecord == NULL)
885 {
886 /* No exception record was passed, so set up a local one */
887 LocalExceptionRecord.ExceptionCode = STATUS_UNWIND;
888 LocalExceptionRecord.ExceptionAddress = (PVOID)ContextRecord->Rip;
889 LocalExceptionRecord.ExceptionRecord = NULL;
890 LocalExceptionRecord.NumberParameters = 0;
891 ExceptionRecord = &LocalExceptionRecord;
892 }
893
894 /* Set unwind flags */
895 ExceptionRecord->ExceptionFlags = EXCEPTION_UNWINDING;
896 if (TargetFrame == NULL)
897 {
898 ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND;
899 }
900
901 /* Call the internal function */
902 RtlpUnwindInternal(TargetFrame,
903 TargetIp,
904 ExceptionRecord,
907 HistoryTable,
909}
#define STATUS_UNWIND
Definition: ntstatus.h:276
@ UNW_FLAG_UHANDLER
Definition: rsym64.h:109
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
void * PVOID
Definition: typedefs.h:50
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:666
#define EXCEPTION_EXIT_UNWIND
Definition: rtltypes.h:156
#define EXCEPTION_UNWINDING
Definition: rtltypes.h:155

Referenced by __C_specific_handler(), and 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 479 of file unwind.c.

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

Referenced by RtlpCaptureNonVolatileContextPointers(), RtlpUnwindInternal(), and RtlWalkFrameChain().

◆ RtlWalkFrameChain()

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

Definition at line 931 of file unwind.c.

934{
936 ULONG64 ControlPc, ImageBase, EstablisherFrame;
937 ULONG64 StackLow, StackHigh;
938 PVOID HandlerData;
939 ULONG i, FramesToSkip;
940 PRUNTIME_FUNCTION FunctionEntry;
941
942 DPRINT("Enter RtlWalkFrameChain\n");
943
944 /* The upper bits in Flags define how many frames to skip */
945 FramesToSkip = Flags >> 8;
946
947 /* Capture the current Context */
949 ControlPc = Context.Rip;
950
951 /* Get the stack limits */
952 RtlpGetStackLimits(&StackLow, &StackHigh);
953
954 /* Check if we want the user-mode stack frame */
955 if (Flags & 1)
956 {
957 }
958
960 {
961 /* Loop the frames */
962 for (i = 0; i < FramesToSkip + Count; i++)
963 {
964 /* Lookup the FunctionEntry for the current ControlPc */
965 FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);
966
967 /* Is this a leaf function? */
968 if (!FunctionEntry)
969 {
970 Context.Rip = *(DWORD64*)Context.Rsp;
971 Context.Rsp += sizeof(DWORD64);
972 DPRINT("leaf funtion, new Rip = %p, new Rsp = %p\n", (PVOID)Context.Rip, (PVOID)Context.Rsp);
973 }
974 else
975 {
977 ImageBase,
978 ControlPc,
979 FunctionEntry,
980 &Context,
981 &HandlerData,
983 NULL);
984 DPRINT("normal funtion, new Rip = %p, new Rsp = %p\n", (PVOID)Context.Rip, (PVOID)Context.Rsp);
985 }
986
987 /* Check if we are in kernel mode */
988 if (RtlpGetMode() == KernelMode)
989 {
990 /* Check if we left the kernel range */
991 if (!(Flags & 1) && (Context.Rip < 0xFFFF800000000000ULL))
992 {
993 break;
994 }
995 }
996 else
997 {
998 /* Check if we left the user range */
999 if ((Context.Rip < 0x10000) ||
1000 (Context.Rip > 0x000007FFFFFEFFFFULL))
1001 {
1002 break;
1003 }
1004 }
1005
1006 /* Check, if we have left our stack */
1007 if ((Context.Rsp <= StackLow) || (Context.Rsp >= StackHigh))
1008 {
1009 break;
1010 }
1011
1012 /* Continue with new Rip */
1013 ControlPc = Context.Rip;
1014
1015 /* Save value, if we are past the frames to skip */
1016 if (i >= FramesToSkip)
1017 {
1018 Callers[i - FramesToSkip] = (PVOID)ControlPc;
1019 }
1020 }
1021 }
1023 {
1024 DPRINT1("Exception while getting callers!\n");
1025 i = 0;
1026 }
1027 _SEH2_END;
1028
1029 DPRINT("RtlWalkFrameChain returns %ld\n", i);
1030 return i;
1031}
#define DPRINT1
Definition: precomp.h:8
KPROCESSOR_MODE NTAPI RtlpGetMode(VOID)
Definition: libsupp.c:53
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
#define UNW_FLAG_NHANDLER
Definition: gs_support.c:32
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:85
#define KernelMode
Definition: asm.h:34
int Count
Definition: noreturn.cpp:7
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:34
#define DPRINT
Definition: sndvol32.h:71
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170

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: xmlstorage.h:181

Referenced by GetEstablisherFrame(), and RtlVirtualUnwind().