ReactOS  0.4.15-dev-2972-gda2a567
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. More...
 
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. More...
 
BOOLEAN NTAPI RtlAddFunctionTable (IN PRUNTIME_FUNCTION FunctionTable, IN DWORD EntryCount, IN DWORD64 BaseAddress)
 
BOOLEAN NTAPI RtlDeleteFunctionTable (IN PRUNTIME_FUNCTION FunctionTable)
 
BOOLEAN NTAPI RtlInstallFunctionTableCallback (IN DWORD64 TableIdentifier, IN DWORD64 BaseAddress, IN DWORD Length, IN PGET_RUNTIME_FUNCTION_CALLBACK Callback, IN PVOID Context, IN PCWSTR OutOfProcessCallbackDll)
 
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, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ ULONG64 ImageBase, _In_ PRUNTIME_FUNCTION FunctionEntry)
 Helper function that tries to unwind epilog instructions. More...
 
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 RtplUnwindInternal (_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 PVOID TargetFrame, IN PVOID TargetIp, IN 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 457 of file unwind.c.

461 {
462  ULONG i;
463 
464  /* Check if we have a frame register */
465  if (UnwindInfo->FrameRegister == 0)
466  {
467  /* No frame register means we use Rsp */
468  return Context->Rsp;
469  }
470 
471  if ((CodeOffset >= UnwindInfo->SizeOfProlog) ||
472  ((UnwindInfo->Flags & UNW_FLAG_CHAININFO) != 0))
473  {
474  return GetReg(Context, UnwindInfo->FrameRegister) -
475  UnwindInfo->FrameOffset * 16;
476  }
477 
478  /* Loop all unwind ops */
479  for (i = 0;
480  i < UnwindInfo->CountOfCodes;
481  i += UnwindOpSlots(UnwindInfo->UnwindCode[i]))
482  {
483  /* Check for SET_FPREG */
484  if (UnwindInfo->UnwindCode[i].UnwindOp == UWOP_SET_FPREG)
485  {
486  return GetReg(Context, UnwindInfo->FrameRegister) -
487  UnwindInfo->FrameOffset * 16;
488  }
489  }
490 
491  return Context->Rsp;
492 }
static __inline DWORD64 GetReg(_In_ PCONTEXT Context, _In_ BYTE Reg)
Definition: unwind.c:264
#define UWOP_SET_FPREG
Definition: unwind.c:22
static __inline ULONG UnwindOpSlots(_In_ UNWIND_CODE UnwindCode)
Definition: unwind.c:204
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
unsigned int ULONG
Definition: retypes.h:1

Referenced by RtlVirtualUnwind().

◆ GetReg()

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

Definition at line 264 of file unwind.c.

267 {
268  return ((DWORD64*)(&Context->Rax))[Reg];
269 }
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 313 of file unwind.c.

314 {
315  return ((M128A*)(&Context->Xmm0))[Reg];
316 }
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 274 of file unwind.c.

278 {
279  SetRegFromStackValue(Context, ContextPointers, Reg, (PDWORD64)Context->Rsp);
280  Context->Rsp += sizeof(DWORD64);
281 }
uint64_t DWORD64
Definition: typedefs.h:67
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:248

Referenced by RtlpTryToUnwindEpilog(), and RtlVirtualUnwind().

◆ RtlAddFunctionTable()

BOOLEAN NTAPI RtlAddFunctionTable ( IN PRUNTIME_FUNCTION  FunctionTable,
IN DWORD  EntryCount,
IN DWORD64  BaseAddress 
)

Definition at line 169 of file unwind.c.

173 {
175  return FALSE;
176 }
#define FALSE
Definition: types.h:117
#define UNIMPLEMENTED
Definition: debug.h:115

◆ RtlDeleteFunctionTable()

BOOLEAN NTAPI RtlDeleteFunctionTable ( IN PRUNTIME_FUNCTION  FunctionTable)

Definition at line 180 of file unwind.c.

182 {
184  return FALSE;
185 }
#define FALSE
Definition: types.h:117
#define UNIMPLEMENTED
Definition: debug.h:115

◆ RtlGetCallersAddress()

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

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

Definition at line 1041 of file unwind.c.

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

◆ RtlInstallFunctionTableCallback()

BOOLEAN NTAPI RtlInstallFunctionTableCallback ( IN DWORD64  TableIdentifier,
IN DWORD64  BaseAddress,
IN DWORD  Length,
IN PGET_RUNTIME_FUNCTION_CALLBACK  Callback,
IN PVOID  Context,
IN PCWSTR  OutOfProcessCallbackDll 
)

Definition at line 189 of file unwind.c.

196 {
198  return FALSE;
199 }
#define FALSE
Definition: types.h:117
#define UNIMPLEMENTED
Definition: debug.h:115

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

121 {
122  PRUNTIME_FUNCTION FunctionTable, FunctionEntry;
123  ULONG TableLength;
124  ULONG IndexLo, IndexHi, IndexMid;
125 
126  /* Find the corresponding table */
127  FunctionTable = RtlLookupFunctionTable(ControlPc, ImageBase, &TableLength);
128 
129  /* Fail, if no table is found */
130  if (!FunctionTable)
131  {
132  return NULL;
133  }
134 
135  /* Use relative virtual address */
136  ControlPc -= *ImageBase;
137 
138  /* Do a binary search */
139  IndexLo = 0;
140  IndexHi = TableLength;
141  while (IndexHi > IndexLo)
142  {
143  IndexMid = (IndexLo + IndexHi) / 2;
144  FunctionEntry = &FunctionTable[IndexMid];
145 
146  if (ControlPc < FunctionEntry->BeginAddress)
147  {
148  /* Continue search in lower half */
149  IndexHi = IndexMid;
150  }
151  else if (ControlPc >= FunctionEntry->EndAddress)
152  {
153  /* Continue search in upper half */
154  IndexLo = IndexMid + 1;
155  }
156  else
157  {
158  /* ControlPc is within limits, return entry */
159  return FunctionEntry;
160  }
161  }
162 
163  /* Nothing found, return NULL */
164  return NULL;
165 }
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
#define NULL
Definition: types.h:112
unsigned int ULONG
Definition: retypes.h:1
static WLX_DISPATCH_VERSION_1_4 FunctionTable
Definition: wlx.c:736

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

◆ 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 {
87  PVOID Table;
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 }
ASMGENDATA Table[]
Definition: genincdata.c:61
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
#define TRUE
Definition: types.h:120
IN PVOID IN PVOID IN USHORT IN USHORT Size
Definition: pci.h:361
PVOID NTAPI RtlPcToFileHeader(IN PVOID PcValue, PVOID *BaseOfImage)
Definition: libsupp.c:659
struct _RUNTIME_FUNCTION RUNTIME_FUNCTION
#define RtlImageDirectoryEntryToData
Definition: compat.h:668
#define NULL
Definition: types.h:112
unsigned int ULONG
Definition: retypes.h:1
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION
Definition: pedump.c:262

Referenced by RtlLookupFunctionEntry().

◆ RtlpCaptureNonVolatileContextPointers()

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

Definition at line 1060 of file unwind.c.

1063 {
1064  CONTEXT Context;
1065  PRUNTIME_FUNCTION FunctionEntry;
1066  ULONG64 ImageBase;
1067  PVOID HandlerData;
1069 
1070  /* Zero out the nonvolatile context pointers */
1071  RtlZeroMemory(NonvolatileContextPointers, sizeof(*NonvolatileContextPointers));
1072 
1073  /* Capture the current context */
1075 
1076  do
1077  {
1078  /* Look up the function entry */
1079  FunctionEntry = RtlLookupFunctionEntry(Context.Rip, &ImageBase, NULL);
1080  ASSERT(FunctionEntry != NULL);
1081 
1082  /* Do a virtual unwind to the caller and capture saved non-volatiles */
1084  ImageBase,
1085  Context.Rip,
1086  FunctionEntry,
1087  &Context,
1088  &HandlerData,
1090  NonvolatileContextPointers);
1091 
1092  /* Make sure nothing fishy is going on. Currently this is for kernel mode only. */
1093  ASSERT(EstablisherFrame != 0);
1094  ASSERT((LONG64)Context.Rip < 0);
1095 
1096  /* Continue until we reached the target frame or user mode */
1097  } while (EstablisherFrame < TargetFrame);
1098 
1099  /* If the caller did the right thing, we should get exactly the target frame */
1100  ASSERT(EstablisherFrame == TargetFrame);
1101 }
_IRQL_requires_same_ _In_ PVOID EstablisherFrame
Definition: ntbasedef.h:653
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:496
NTSYSAPI VOID NTAPI RtlCaptureContext(_Out_ PCONTEXT ContextRecord)
int64_t LONG64
Definition: typedefs.h:68
#define ASSERT(a)
Definition: mode.c:44
unsigned __int64 ULONG64
Definition: imports.h:198
#define NULL
Definition: types.h:112
struct tagContext Context
Definition: acpixf.h:1034
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
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:117

Referenced by RtlSetUnwindContext().

◆ RtlpTryToUnwindEpilog()

static __inline BOOLEAN RtlpTryToUnwindEpilog ( _Inout_ PCONTEXT  Context,
_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 331 of file unwind.c.

336 {
337  CONTEXT LocalContext;
338  BYTE *InstrPtr;
339  DWORD Instr;
340  BYTE Reg, Mod;
341  ULONG64 EndAddress;
342 
343  /* Make a local copy of the context */
344  LocalContext = *Context;
345 
346  InstrPtr = (BYTE*)LocalContext.Rip;
347 
348  /* Check if first instruction of epilog is "add rsp, x" */
349  Instr = *(DWORD*)InstrPtr;
350  if ( (Instr & 0x00fffdff) == 0x00c48148 )
351  {
352  if ( (Instr & 0x0000ff00) == 0x8300 )
353  {
354  /* This is "add rsp, 0x??" */
355  LocalContext.Rsp += Instr >> 24;
356  InstrPtr += 4;
357  }
358  else
359  {
360  /* This is "add rsp, 0x???????? */
361  LocalContext.Rsp += *(DWORD*)(InstrPtr + 3);
362  InstrPtr += 7;
363  }
364  }
365  /* Check if first instruction of epilog is "lea rsp, ..." */
366  else if ( (Instr & 0x38fffe) == 0x208d48 )
367  {
368  /* Get the register */
369  Reg = ((Instr << 8) | (Instr >> 16)) & 0x7;
370 
371  LocalContext.Rsp = GetReg(&LocalContext, Reg);
372 
373  /* Get adressing mode */
374  Mod = (Instr >> 22) & 0x3;
375  if (Mod == 0)
376  {
377  /* No displacement */
378  InstrPtr += 3;
379  }
380  else if (Mod == 1)
381  {
382  /* 1 byte displacement */
383  LocalContext.Rsp += Instr >> 24;
384  InstrPtr += 4;
385  }
386  else if (Mod == 2)
387  {
388  /* 4 bytes displacement */
389  LocalContext.Rsp += *(DWORD*)(InstrPtr + 3);
390  InstrPtr += 7;
391  }
392  }
393 
394  /* Loop the following instructions before the ret */
395  EndAddress = FunctionEntry->EndAddress + ImageBase - 1;
396  while ((DWORD64)InstrPtr < EndAddress)
397  {
398  Instr = *(DWORD*)InstrPtr;
399 
400  /* Check for a simple pop */
401  if ( (Instr & 0xf8) == 0x58 )
402  {
403  /* Opcode pops a basic register from stack */
404  Reg = Instr & 0x7;
405  PopReg(&LocalContext, ContextPointers, Reg);
406  InstrPtr++;
407  continue;
408  }
409 
410  /* Check for REX + pop */
411  if ( (Instr & 0xf8fb) == 0x5841 )
412  {
413  /* Opcode is pop r8 .. r15 */
414  Reg = ((Instr >> 8) & 0x7) + 8;
415  PopReg(&LocalContext, ContextPointers, Reg);
416  InstrPtr += 2;
417  continue;
418  }
419 
420  /* Opcode not allowed for Epilog */
421  return FALSE;
422  }
423 
424  // check for popfq
425 
426  // also allow end with jmp imm, jmp [target], iretq
427 
428  /* Check if we are at the ret instruction */
429  if ((DWORD64)InstrPtr != EndAddress)
430  {
431  /* If we went past the end of the function, something is broken! */
432  ASSERT((DWORD64)InstrPtr <= EndAddress);
433  return FALSE;
434  }
435 
436  /* Make sure this is really a ret instruction */
437  if (*InstrPtr != 0xc3)
438  {
439  ASSERT(FALSE);
440  return FALSE;
441  }
442 
443  /* Unwind is finished, pop new Rip from Stack */
444  LocalContext.Rip = *(DWORD64*)LocalContext.Rsp;
445  LocalContext.Rsp += sizeof(DWORD64);
446 
447  *Context = LocalContext;
448  return TRUE;
449 }
#define TRUE
Definition: types.h:120
static __inline DWORD64 GetReg(_In_ PCONTEXT Context, _In_ BYTE Reg)
Definition: unwind.c:264
#define FALSE
Definition: types.h:117
#define ASSERT(a)
Definition: mode.c:44
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned __int64 ULONG64
Definition: imports.h:198
unsigned char BYTE
Definition: xxhash.c:193
uint64_t DWORD64
Definition: typedefs.h:67
static __inline void PopReg(_Inout_ PCONTEXT Context, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ BYTE Reg)
Definition: unwind.c:274
struct tagContext Context
Definition: acpixf.h:1034

Referenced by RtlVirtualUnwind().

◆ RtlSetUnwindContext()

VOID RtlSetUnwindContext ( _In_ PCONTEXT  Context,
_In_ DWORD64  TargetFrame 
)

Definition at line 1104 of file unwind.c.

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

Referenced by KiSetTrapContextInternal().

◆ RtlUnwind()

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

Definition at line 921 of file unwind.c.

926 {
928  return;
929 }
#define UNIMPLEMENTED
Definition: debug.h:115

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

892 {
893  EXCEPTION_RECORD LocalExceptionRecord;
894 
895  /* Capture the current context */
897 
898  /* Check if we have an exception record */
899  if (ExceptionRecord == NULL)
900  {
901  /* No exception record was passed, so set up a local one */
902  LocalExceptionRecord.ExceptionCode = STATUS_UNWIND;
903  LocalExceptionRecord.ExceptionAddress = (PVOID)ContextRecord->Rip;
904  LocalExceptionRecord.ExceptionRecord = NULL;
905  LocalExceptionRecord.NumberParameters = 0;
906  ExceptionRecord = &LocalExceptionRecord;
907  }
908 
909  /* Call the internal function */
910  RtplUnwindInternal(TargetFrame,
911  TargetIp,
912  ExceptionRecord,
913  ReturnValue,
915  HistoryTable,
917 }
NTSYSAPI VOID NTAPI RtlCaptureContext(_Out_ PCONTEXT ContextRecord)
PVOID ExceptionAddress
Definition: compat.h:211
DWORD ExceptionCode
Definition: compat.h:208
UINT32 void void ** ReturnValue
Definition: acevents.h:214
void * PVOID
Definition: retypes.h:9
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT * ContextRecord
Definition: ntbasedef.h:654
struct _EXCEPTION_RECORD * ExceptionRecord
Definition: compat.h:210
BOOLEAN NTAPI RtplUnwindInternal(_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:686
#define STATUS_UNWIND
Definition: ntstatus.h:276
#define NULL
Definition: types.h:112
DWORD NumberParameters
Definition: compat.h:212

Referenced by __C_specific_handler().

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

505 {
506  PUNWIND_INFO UnwindInfo;
507  ULONG_PTR CodeOffset;
508  ULONG i, Offset;
509  UNWIND_CODE UnwindCode;
510  BYTE Reg;
511  PULONG LanguageHandler;
512 
513  /* Use relative virtual address */
514  ControlPc -= ImageBase;
515 
516  /* Sanity checks */
517  if ( (ControlPc < FunctionEntry->BeginAddress) ||
518  (ControlPc >= FunctionEntry->EndAddress) )
519  {
520  return NULL;
521  }
522 
523  /* Get a pointer to the unwind info */
524  UnwindInfo = RVA(ImageBase, FunctionEntry->UnwindData);
525 
526  /* The language specific handler data follows the unwind info */
527  LanguageHandler = ALIGN_UP_POINTER_BY(&UnwindInfo->UnwindCode[UnwindInfo->CountOfCodes], sizeof(ULONG));
528  *HandlerData = (LanguageHandler + 1);
529 
530  /* Calculate relative offset to function start */
531  CodeOffset = ControlPc - FunctionEntry->BeginAddress;
532 
533  *EstablisherFrame = GetEstablisherFrame(Context, UnwindInfo, CodeOffset);
534 
535  /* Check if we are in the function epilog and try to finish it */
536  if (CodeOffset > UnwindInfo->SizeOfProlog)
537  {
538  if (RtlpTryToUnwindEpilog(Context, ContextPointers, ImageBase, FunctionEntry))
539  {
540  /* There's no exception routine */
541  return NULL;
542  }
543  }
544 
545  /* Skip all Ops with an offset greater than the current Offset */
546  i = 0;
547  while ((i < UnwindInfo->CountOfCodes) &&
548  (UnwindInfo->UnwindCode[i].CodeOffset > CodeOffset))
549  {
550  i += UnwindOpSlots(UnwindInfo->UnwindCode[i]);
551  }
552 
553 RepeatChainedInfo:
554 
555  /* Process the remaining unwind ops */
556  while (i < UnwindInfo->CountOfCodes)
557  {
558  UnwindCode = UnwindInfo->UnwindCode[i];
559  switch (UnwindCode.UnwindOp)
560  {
561  case UWOP_PUSH_NONVOL:
562  Reg = UnwindCode.OpInfo;
563  PopReg(Context, ContextPointers, Reg);
564  i++;
565  break;
566 
567  case UWOP_ALLOC_LARGE:
568  if (UnwindCode.OpInfo)
569  {
570  Offset = *(ULONG*)(&UnwindInfo->UnwindCode[i+1]);
571  Context->Rsp += Offset;
572  i += 3;
573  }
574  else
575  {
576  Offset = UnwindInfo->UnwindCode[i+1].FrameOffset;
577  Context->Rsp += Offset * 8;
578  i += 2;
579  }
580  break;
581 
582  case UWOP_ALLOC_SMALL:
583  Context->Rsp += (UnwindCode.OpInfo + 1) * 8;
584  i++;
585  break;
586 
587  case UWOP_SET_FPREG:
588  Reg = UnwindInfo->FrameRegister;
589  Context->Rsp = GetReg(Context, Reg) - UnwindInfo->FrameOffset * 16;
590  i++;
591  break;
592 
593  case UWOP_SAVE_NONVOL:
594  Reg = UnwindCode.OpInfo;
595  Offset = *(USHORT*)(&UnwindInfo->UnwindCode[i + 1]);
596  SetRegFromStackValue(Context, ContextPointers, Reg, (DWORD64*)Context->Rsp + Offset);
597  i += 2;
598  break;
599 
601  Reg = UnwindCode.OpInfo;
602  Offset = *(ULONG*)(&UnwindInfo->UnwindCode[i + 1]);
603  SetRegFromStackValue(Context, ContextPointers, Reg, (DWORD64*)Context->Rsp + Offset);
604  i += 3;
605  break;
606 
607  case UWOP_EPILOG:
608  i += 1;
609  break;
610 
611  case UWOP_SPARE_CODE:
612  ASSERT(FALSE);
613  i += 2;
614  break;
615 
616  case UWOP_SAVE_XMM128:
617  Reg = UnwindCode.OpInfo;
618  Offset = *(USHORT*)(&UnwindInfo->UnwindCode[i + 1]);
619  SetXmmRegFromStackValue(Context, ContextPointers, Reg, (M128A*)(Context->Rsp + Offset));
620  i += 2;
621  break;
622 
624  Reg = UnwindCode.OpInfo;
625  Offset = *(ULONG*)(&UnwindInfo->UnwindCode[i + 1]);
626  SetXmmRegFromStackValue(Context, ContextPointers, Reg, (M128A*)(Context->Rsp + Offset));
627  i += 3;
628  break;
629 
630  case UWOP_PUSH_MACHFRAME:
631  /* OpInfo is 1, when an error code was pushed, otherwise 0. */
632  Context->Rsp += UnwindCode.OpInfo * sizeof(DWORD64);
633 
634  /* Now pop the MACHINE_FRAME (Yes, "magic numbers", deal with it) */
635  Context->Rip = *(PDWORD64)(Context->Rsp + 0x00);
636  Context->SegCs = *(PDWORD64)(Context->Rsp + 0x08);
637  Context->EFlags = *(PDWORD64)(Context->Rsp + 0x10);
638  Context->SegSs = *(PDWORD64)(Context->Rsp + 0x20);
639  Context->Rsp = *(PDWORD64)(Context->Rsp + 0x18);
640  ASSERT((i + 1) == UnwindInfo->CountOfCodes);
641  goto Exit;
642  }
643  }
644 
645  /* Check for chained info */
646  if (UnwindInfo->Flags & UNW_FLAG_CHAININFO)
647  {
648  /* See https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64?view=msvc-160#chained-unwind-info-structures */
649  FunctionEntry = (PRUNTIME_FUNCTION)&(UnwindInfo->UnwindCode[(UnwindInfo->CountOfCodes + 1) & ~1]);
650  UnwindInfo = RVA(ImageBase, FunctionEntry->UnwindData);
651  i = 0;
652  goto RepeatChainedInfo;
653  }
654 
655  /* Unwind is finished, pop new Rip from Stack */
656  if (Context->Rsp != 0)
657  {
658  Context->Rip = *(DWORD64*)Context->Rsp;
659  Context->Rsp += sizeof(DWORD64);
660  }
661 
662 Exit:
663 
664  /* Check if we have a handler and return it */
665  if (UnwindInfo->Flags & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER))
666  {
667  return RVA(ImageBase, *LanguageHandler);
668  }
669 
670  return NULL;
671 }
_IRQL_requires_same_ _In_ PVOID EstablisherFrame
Definition: ntbasedef.h:653
BYTE FrameOffset
Definition: cpu_x86_64.c:67
M128A
Definition: ketypes.h:925
static __inline BOOLEAN RtlpTryToUnwindEpilog(_Inout_ PCONTEXT Context, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ ULONG64 ImageBase, _In_ PRUNTIME_FUNCTION FunctionEntry)
Helper function that tries to unwind epilog instructions.
Definition: unwind.c:331
#define UWOP_SPARE_CODE
Definition: unwind.c:30
BYTE UnwindOp
Definition: cpu_x86_64.c:54
static ULONG64 GetEstablisherFrame(_In_ PCONTEXT Context, _In_ PUNWIND_INFO UnwindInfo, _In_ ULONG_PTR CodeOffset)
Definition: unwind.c:457
#define UWOP_EPILOG
Definition: unwind.c:29
static __inline DWORD64 GetReg(_In_ PCONTEXT Context, _In_ BYTE Reg)
Definition: unwind.c:264
#define UWOP_PUSH_NONVOL
Definition: unwind.c:19
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define UWOP_SET_FPREG
Definition: unwind.c:22
#define FALSE
Definition: types.h:117
BYTE CodeOffset
Definition: cpu_x86_64.c:53
#define UWOP_ALLOC_LARGE
Definition: unwind.c:20
#define UWOP_SAVE_XMM128_FAR
Definition: unwind.c:33
#define UWOP_PUSH_MACHFRAME
Definition: unwind.c:34
static __inline void SetXmmRegFromStackValue(_Out_ PCONTEXT Context, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ BYTE Reg, _In_ M128A *ValuePointer)
Definition: unwind.c:297
#define ASSERT(a)
Definition: mode.c:44
BYTE FrameRegister
Definition: cpu_x86_64.c:66
static void Exit(void)
Definition: sock.c:1331
#define UWOP_SAVE_XMM128
Definition: unwind.c:32
static __inline ULONG UnwindOpSlots(_In_ UNWIND_CODE UnwindCode)
Definition: unwind.c:204
#define UWOP_ALLOC_SMALL
Definition: unwind.c:21
struct _RUNTIME_FUNCTION * PRUNTIME_FUNCTION
#define ALIGN_UP_POINTER_BY(ptr, align)
Definition: umtypes.h:85
UNWIND_CODE UnwindCode[1]
Definition: cpu_x86_64.c:68
unsigned char BYTE
Definition: xxhash.c:193
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
#define RVA(m, b)
Definition: freeldr.h:24
BYTE SizeOfProlog
Definition: cpu_x86_64.c:64
USHORT FrameOffset
Definition: cpu_x86_64.c:57
uint64_t DWORD64
Definition: typedefs.h:67
static __inline void PopReg(_Inout_ PCONTEXT Context, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ BYTE Reg)
Definition: unwind.c:274
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
unsigned short USHORT
Definition: pedump.c:61
unsigned int * PULONG
Definition: retypes.h:1
#define NULL
Definition: types.h:112
#define UWOP_SAVE_NONVOL_FAR
Definition: unwind.c:24
unsigned int ULONG
Definition: retypes.h:1
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:248
#define UWOP_SAVE_NONVOL
Definition: unwind.c:23
BYTE CountOfCodes
Definition: cpu_x86_64.c:65

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

◆ RtlWalkFrameChain()

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

Definition at line 933 of file unwind.c.

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

Referenced by RtlGetCallersAddress().

◆ RtplUnwindInternal()

BOOLEAN NTAPI RtplUnwindInternal ( _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 686 of file unwind.c.

694 {
696  PEXCEPTION_ROUTINE ExceptionRoutine;
698  PRUNTIME_FUNCTION FunctionEntry;
699  ULONG_PTR StackLow, StackHigh;
700  ULONG64 ImageBase, EstablisherFrame;
701  CONTEXT UnwindContext;
702 
703  /* Get the current stack limits and registration frame */
704  RtlpGetStackLimits(&StackLow, &StackHigh);
705 
706  /* If we have a target frame, then this is our high limit */
707  if (TargetFrame != NULL)
708  {
709  StackHigh = (ULONG64)TargetFrame + 1;
710  }
711 
712  /* Copy the context */
713  UnwindContext = *ContextRecord;
714 
715  /* Set up the constant fields of the dispatcher context */
716  DispatcherContext.ContextRecord = ContextRecord;
717  DispatcherContext.HistoryTable = HistoryTable;
718  DispatcherContext.TargetIp = (ULONG64)TargetIp;
719 
720  /* Start looping */
721  while (TRUE)
722  {
723  /* Lookup the FunctionEntry for the current RIP */
724  FunctionEntry = RtlLookupFunctionEntry(UnwindContext.Rip, &ImageBase, NULL);
725  if (FunctionEntry == NULL)
726  {
727  /* No function entry, so this must be a leaf function. Pop the return address from the stack.
728  Note: this can happen after the first frame as the result of an exception */
729  UnwindContext.Rip = *(DWORD64*)UnwindContext.Rsp;
730  UnwindContext.Rsp += sizeof(DWORD64);
731  continue;
732  }
733 
734  /* Do a virtual unwind to get the next frame */
735  ExceptionRoutine = RtlVirtualUnwind(HandlerType,
736  ImageBase,
737  UnwindContext.Rip,
738  FunctionEntry,
739  &UnwindContext,
740  &DispatcherContext.HandlerData,
742  NULL);
743 
744  /* Check, if we are still within the stack boundaries */
745  if ((EstablisherFrame < StackLow) ||
746  (EstablisherFrame >= StackHigh) ||
747  (EstablisherFrame & 7))
748  {
750 
751  /* If we are handling an exception, we are done here. */
753  {
754  ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
755  return FALSE;
756  }
757 
758  __debugbreak();
760  }
761 
762  /* Check if we have an exception routine */
763  if (ExceptionRoutine != NULL)
764  {
765  /* Check if this is the target frame */
766  if (EstablisherFrame == (ULONG64)TargetFrame)
767  {
768  /* Set flag to inform the language handler */
769  ExceptionRecord->ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
770  }
771 
772  /* Log the exception if it's enabled */
773  RtlpCheckLogException(ExceptionRecord,
776  sizeof(DispatcherContext));
777 
778  /* Set up the variable fields of the dispatcher context */
779  DispatcherContext.ControlPc = ContextRecord->Rip;
780  DispatcherContext.ImageBase = ImageBase;
781  DispatcherContext.FunctionEntry = FunctionEntry;
782  DispatcherContext.LanguageHandler = ExceptionRoutine;
783  DispatcherContext.EstablisherFrame = EstablisherFrame;
784  DispatcherContext.ScopeIndex = 0;
785 
786  /* Store the return value in the unwind context */
787  UnwindContext.Rax = (ULONG64)ReturnValue;
788 
789  /* Loop all nested handlers */
790  do
791  {
793  /* Call the language specific handler */
794  Disposition = ExceptionRoutine(ExceptionRecord,
796  &UnwindContext,
798 
799  /* Clear exception flags for the next iteration */
800  ExceptionRecord->ExceptionFlags &= ~(EXCEPTION_TARGET_UNWIND |
802 
803  /* Check if we do exception handling */
805  {
807  {
808  /* Check if it was non-continuable */
809  if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
810  {
811  __debugbreak();
813  }
814 
815  /* Execution continues */
816  return TRUE;
817  }
819  {
821  __debugbreak();
822  }
823  }
824 
826  {
828  __debugbreak();
829  }
830 
831  /* This must be ExceptionContinueSearch now */
833  {
834  __debugbreak();
836  }
837  } while (ExceptionRecord->ExceptionFlags & EXCEPTION_COLLIDED_UNWIND);
838  }
839 
840  /* Check, if we have left our stack (8.) */
841  if ((EstablisherFrame < StackLow) ||
842  (EstablisherFrame > StackHigh) ||
843  (EstablisherFrame & 7))
844  {
846  __debugbreak();
847 
848  if (UnwindContext.Rip == ContextRecord->Rip)
849  {
851  }
852  else
853  {
854  ZwRaiseException(ExceptionRecord, ContextRecord, FALSE);
855  }
856  }
857 
858  if (EstablisherFrame == (ULONG64)TargetFrame)
859  {
860  break;
861  }
862 
863  /* We have successfully unwound a frame. Copy the unwind context back. */
864  *ContextRecord = UnwindContext;
865  }
866 
867  if (ExceptionRecord->ExceptionCode != STATUS_UNWIND_CONSOLIDATE)
868  {
869  ContextRecord->Rip = (ULONG64)TargetIp;
870  }
871 
872  /* Set the return value */
874 
875  /* Restore the context */
876  RtlRestoreContext(ContextRecord, ExceptionRecord);
877 
878  /* Should never get here! */
879  ASSERT(FALSE);
880  return FALSE;
881 }
#define STATUS_UNWIND_CONSOLIDATE
Definition: ntstatus.h:220
#define EXCEPTION_NONCONTINUABLE_EXCEPTION
Definition: winbase.h:325
DECLSPEC_NORETURN NTSYSAPI VOID NTAPI RtlRaiseStatus(_In_ NTSTATUS Status)
_IRQL_requires_same_ _In_ PVOID EstablisherFrame
Definition: ntbasedef.h:653
#define TRUE
Definition: types.h:120
#define STATUS_BAD_STACK
Definition: ntstatus.h:277
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:496
NTSYSAPI NTSTATUS NTAPI ZwRaiseException(_In_ PEXCEPTION_RECORD ExceptionRecord, _In_ PCONTEXT Context, _In_ BOOLEAN SearchFrames)
#define EXCEPTION_NONCONTINUABLE
Definition: rtltypes.h:154
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:50
#define STATUS_BAD_FUNCTION_TABLE
Definition: ntstatus.h:491
uint32_t ULONG_PTR
Definition: typedefs.h:65
ACPI_PHYSICAL_ADDRESS ACPI_SIZE BOOLEAN Warn BOOLEAN Physical 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:813
UINT32 void void ** ReturnValue
Definition: acevents.h:214
#define FALSE
Definition: types.h:117
#define STATUS_INVALID_DISPOSITION
Definition: ntstatus.h:275
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT _In_ PVOID DispatcherContext
Definition: ntbasedef.h:654
#define EXCEPTION_TARGET_UNWIND
Definition: rtltypes.h:159
#define EXCEPTION_STACK_INVALID
Definition: rtltypes.h:157
EXCEPTION_ROUTINE * PEXCEPTION_ROUTINE
Definition: compat.h:568
#define ASSERT(a)
Definition: mode.c:44
#define EXCEPTION_COLLIDED_UNWIND
Definition: rtltypes.h:160
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT * ContextRecord
Definition: ntbasedef.h:654
unsigned __int64 ULONG64
Definition: imports.h:198
VOID NTAPI RtlpGetStackLimits(PULONG_PTR StackBase, PULONG_PTR StackLimit)
uint64_t DWORD64
Definition: typedefs.h:67
#define NULL
Definition: types.h:112
VOID NTAPI RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord, IN PVOID ContextData, IN ULONG Size)
Definition: libsupp.c:201
enum _EXCEPTION_DISPOSITION EXCEPTION_DISPOSITION
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:117

Referenced by RtlDispatchException(), and RtlUnwindEx().

◆ SetReg()

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

Definition at line 237 of file unwind.c.

241 {
242  ((DWORD64*)(&Context->Rax))[Reg] = Value;
243 }
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:406
uint64_t DWORD64
Definition: typedefs.h:67

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

253 {
254  SetReg(Context, Reg, *ValuePointer);
255  if (ContextPointers != NULL)
256  {
257  ContextPointers->IntegerContext[Reg] = ValuePointer;
258  }
259 }
static __inline void SetReg(_Inout_ PCONTEXT Context, _In_ BYTE Reg, _In_ DWORD64 Value)
Definition: unwind.c:237
#define NULL
Definition: types.h:112

Referenced by PopReg(), and RtlVirtualUnwind().

◆ SetXmmReg()

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

Definition at line 286 of file unwind.c.

290 {
291  ((M128A*)(&Context->Xmm0))[Reg] = Value;
292 }
M128A
Definition: ketypes.h:925
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:406

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

302 {
303  SetXmmReg(Context, Reg, *ValuePointer);
304  if (ContextPointers != NULL)
305  {
306  ContextPointers->FloatingContext[Reg] = ValuePointer;
307  }
308 }
#define NULL
Definition: types.h:112
static __inline void SetXmmReg(_Inout_ PCONTEXT Context, _In_ BYTE Reg, _In_ M128A Value)
Definition: unwind.c:286

Referenced by RtlVirtualUnwind().

◆ UnwindOpSlots()

static __inline ULONG UnwindOpSlots ( _In_ UNWIND_CODE  UnwindCode)
static

Definition at line 204 of file unwind.c.

206 {
207  static const UCHAR UnwindOpExtraSlotTable[] =
208  {
209  0, // UWOP_PUSH_NONVOL
210  1, // UWOP_ALLOC_LARGE (or 3, special cased in lookup code)
211  0, // UWOP_ALLOC_SMALL
212  0, // UWOP_SET_FPREG
213  1, // UWOP_SAVE_NONVOL
214  2, // UWOP_SAVE_NONVOL_FAR
215  1, // UWOP_EPILOG // previously UWOP_SAVE_XMM
216  2, // UWOP_SPARE_CODE // previously UWOP_SAVE_XMM_FAR
217  1, // UWOP_SAVE_XMM128
218  2, // UWOP_SAVE_XMM128_FAR
219  0, // UWOP_PUSH_MACHFRAME
220  2, // UWOP_SET_FPREG_LARGE
221  };
222 
223  if ((UnwindCode.UnwindOp == UWOP_ALLOC_LARGE) &&
224  (UnwindCode.OpInfo != 0))
225  {
226  return 3;
227  }
228  else
229  {
230  return UnwindOpExtraSlotTable[UnwindCode.UnwindOp] + 1;
231  }
232 }
#define UWOP_ALLOC_LARGE
Definition: unwind.c:20
unsigned char UCHAR
Definition: xmlstorage.h:181

Referenced by GetEstablisherFrame(), and RtlVirtualUnwind().