ReactOS 0.4.17-dev-243-g1369312
RtlVirtualUnwind.c File Reference
#include <rtltests.h>
Include dependency graph for RtlVirtualUnwind.c:

Go to the source code of this file.

Classes

union  _TEST_UNWIND_CODE
 
struct  _TEST_UNWIND_INFO
 
struct  _IMAGE_STRUCT
 

Macros

#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
 
#define PARENT_OFFSET   0x100 /* Offset of the parent unwind info inside Unwind[]. */
 
#define INIT_RAX   0xDEADBEEFDEADBEEFULL
 

Typedefs

typedef union _TEST_UNWIND_CODE TEST_UNWIND_CODE
 
typedef struct _TEST_UNWIND_INFO TEST_UNWIND_INFO
 
typedef struct _IMAGE_STRUCT IMAGE_STRUCT
 

Enumerations

enum  {
  REG_RAX = 0 , REG_RCX , REG_RDX , REG_RBX ,
  REG_RSP , REG_RBP , REG_RSI , REG_RDI ,
  REG_R8 , REG_R9 , REG_R10 , REG_R11 ,
  REG_R12 , REG_R13 , REG_R14 , REG_R15
}
 

Functions

static DECLSPEC_ALIGN (16)
 
static VOID SetCode (TEST_UNWIND_INFO *Info, ULONG Index, UCHAR CodeOffset, UCHAR UnwindOp, UCHAR OpInfo)
 
static VOID InitContext (PCONTEXT Context, ULONG_PTR Rsp)
 
static ULONG_PTR DoUnwind (PCONTEXT Context, ULONG CodeOffset, PKNONVOLATILE_CONTEXT_POINTERS Pointers)
 
static ULONG_PTR RunUnwind (PCONTEXT Context, ULONG_PTR Rsp, ULONG CodeOffset, PKNONVOLATILE_CONTEXT_POINTERS Pointers)
 
static VOID Test_PushNonvol (VOID)
 
static VOID Test_AllocSmall (VOID)
 
static VOID Test_AllocLargeScaled (VOID)
 
static VOID Test_AllocLargeUnscaled (VOID)
 
static VOID Test_SetFpReg (VOID)
 
static VOID Test_SaveNonvol (VOID)
 
static VOID Test_SaveXmm128 (VOID)
 
static VOID Test_PushMachframe (VOID)
 
static VOID Test_TypicalProlog (VOID)
 
static VOID Test_PartialProlog (VOID)
 
static VOID Test_ContextPointers (VOID)
 
static VOID Test_ChainedInfo (VOID)
 
static VOID Test_SaveNonvolFar (VOID)
 
static VOID Test_SaveXmm128Far (VOID)
 
static VOID Test_Epilog (VOID)
 
static VOID Test_SpareCode (VOID)
 
 START_TEST (RtlVirtualUnwind)
 

Macro Definition Documentation

◆ INIT_RAX

#define INIT_RAX   0xDEADBEEFDEADBEEFULL

Definition at line 69 of file RtlVirtualUnwind.c.

◆ PARENT_OFFSET

#define PARENT_OFFSET   0x100 /* Offset of the parent unwind info inside Unwind[]. */

Definition at line 67 of file RtlVirtualUnwind.c.

◆ UWOP_ALLOC_LARGE

#define UWOP_ALLOC_LARGE   1

Definition at line 11 of file RtlVirtualUnwind.c.

◆ UWOP_ALLOC_SMALL

#define UWOP_ALLOC_SMALL   2

Definition at line 12 of file RtlVirtualUnwind.c.

◆ UWOP_EPILOG

#define UWOP_EPILOG   6

Definition at line 16 of file RtlVirtualUnwind.c.

◆ UWOP_PUSH_MACHFRAME

#define UWOP_PUSH_MACHFRAME   10

Definition at line 20 of file RtlVirtualUnwind.c.

◆ UWOP_PUSH_NONVOL

#define UWOP_PUSH_NONVOL   0

Definition at line 10 of file RtlVirtualUnwind.c.

◆ UWOP_SAVE_NONVOL

#define UWOP_SAVE_NONVOL   4

Definition at line 14 of file RtlVirtualUnwind.c.

◆ UWOP_SAVE_NONVOL_FAR

#define UWOP_SAVE_NONVOL_FAR   5

Definition at line 15 of file RtlVirtualUnwind.c.

◆ UWOP_SAVE_XMM128

#define UWOP_SAVE_XMM128   8

Definition at line 18 of file RtlVirtualUnwind.c.

◆ UWOP_SAVE_XMM128_FAR

#define UWOP_SAVE_XMM128_FAR   9

Definition at line 19 of file RtlVirtualUnwind.c.

◆ UWOP_SET_FPREG

#define UWOP_SET_FPREG   3

Definition at line 13 of file RtlVirtualUnwind.c.

◆ UWOP_SPARE_CODE

#define UWOP_SPARE_CODE   7

Definition at line 17 of file RtlVirtualUnwind.c.

Typedef Documentation

◆ IMAGE_STRUCT

◆ TEST_UNWIND_CODE

◆ TEST_UNWIND_INFO

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
REG_RAX 
REG_RCX 
REG_RDX 
REG_RBX 
REG_RSP 
REG_RBP 
REG_RSI 
REG_RDI 
REG_R8 
REG_R9 
REG_R10 
REG_R11 
REG_R12 
REG_R13 
REG_R14 
REG_R15 

Definition at line 24 of file RtlVirtualUnwind.c.

25{
30};
@ REG_RBP
@ REG_R8
@ REG_R14
@ REG_RSP
@ REG_R11
@ REG_RCX
@ REG_RDX
@ REG_R13
@ REG_RDI
@ REG_R12
@ REG_RAX
@ REG_R15
@ REG_R10
@ REG_RBX
@ REG_RSI
@ REG_R9

Function Documentation

◆ DECLSPEC_ALIGN()

static DECLSPEC_ALIGN ( 16  )
static

Definition at line 71 of file RtlVirtualUnwind.c.

81{
82 TEST_UNWIND_INFO *Info = (TEST_UNWIND_INFO *)g_Image.Unwind;
83 RtlZeroMemory(Info, sizeof(*Info));
84 Info->Version = Version;
85 Info->SizeOfProlog = SizeOfProlog;
86 Info->CountOfCodes = CountOfCodes;
87 return Info;
88}
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
_Must_inspect_result_ _In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR _Out_ WDFDEVICE _Inout_opt_ PWDF_CHILD_RETRIEVE_INFO Info
Definition: wdfchildlist.h:690
_Must_inspect_result_ _In_ WDFDEVICE _In_ LPCGUID _Out_ PINTERFACE _In_ USHORT _In_ USHORT Version
Definition: wdffdo.h:469

◆ DoUnwind()

static ULONG_PTR DoUnwind ( PCONTEXT  Context,
ULONG  CodeOffset,
PKNONVOLATILE_CONTEXT_POINTERS  Pointers 
)
static

Definition at line 108 of file RtlVirtualUnwind.c.

110{
111 RUNTIME_FUNCTION Func =
112 {
116 };
117 PVOID HandlerData = NULL;
119
121 (ULONG_PTR)&g_Image,
122 (ULONG_PTR)g_Image.Code + CodeOffset,
123 &Func,
124 Context,
125 &HandlerData,
127 Pointers);
128 return EstablisherFrame;
129}
#define NULL
Definition: types.h:112
#define UNW_FLAG_NHANDLER
Definition: gs_support.c:32
_IRQL_requires_same_ _In_ PVOID EstablisherFrame
Definition: ntbasedef.h:665
void(* Func)(int)
NTSYSAPI PEXCEPTION_ROUTINE WINAPI RtlVirtualUnwind(ULONG, ULONG_PTR, ULONG_PTR, RUNTIME_FUNCTION *, CONTEXT *, void **, ULONG_PTR *, KNONVOLATILE_CONTEXT_POINTERS *)
_In_ PVOID Context
Definition: storport.h:2269
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
uint32_t ULONG_PTR
Definition: typedefs.h:65
_In_ UCHAR _In_ UCHAR _In_ ULONG Code
Definition: wdfdevice.h:1707

Referenced by RunUnwind(), and Test_SetFpReg().

◆ InitContext()

static VOID InitContext ( PCONTEXT  Context,
ULONG_PTR  Rsp 
)
static

Definition at line 100 of file RtlVirtualUnwind.c.

101{
102 RtlZeroMemory(Context, sizeof(*Context));
103 Context->Rsp = Rsp;
104 Context->Rax = INIT_RAX;
105}
#define INIT_RAX

Referenced by RunUnwind(), and Test_SetFpReg().

◆ RunUnwind()

static ULONG_PTR RunUnwind ( PCONTEXT  Context,
ULONG_PTR  Rsp,
ULONG  CodeOffset,
PKNONVOLATILE_CONTEXT_POINTERS  Pointers 
)
static

Definition at line 132 of file RtlVirtualUnwind.c.

134{
135 InitContext(Context, Rsp);
136 return DoUnwind(Context, CodeOffset, Pointers);
137}
static ULONG_PTR DoUnwind(PCONTEXT Context, ULONG CodeOffset, PKNONVOLATILE_CONTEXT_POINTERS Pointers)
static VOID InitContext(PCONTEXT Context, ULONG_PTR Rsp)

Referenced by Test_AllocLargeScaled(), Test_AllocLargeUnscaled(), Test_AllocSmall(), Test_ChainedInfo(), Test_ContextPointers(), Test_Epilog(), Test_PartialProlog(), Test_PushMachframe(), Test_PushNonvol(), Test_SaveNonvol(), Test_SaveNonvolFar(), Test_SaveXmm128(), Test_SaveXmm128Far(), Test_SpareCode(), and Test_TypicalProlog().

◆ SetCode()

static VOID SetCode ( TEST_UNWIND_INFO Info,
ULONG  Index,
UCHAR  CodeOffset,
UCHAR  UnwindOp,
UCHAR  OpInfo 
)
static

Definition at line 91 of file RtlVirtualUnwind.c.

93{
94 Info->UnwindCode[Index].CodeOffset = CodeOffset;
95 Info->UnwindCode[Index].UnwindOp = UnwindOp;
96 Info->UnwindCode[Index].OpInfo = OpInfo;
97}
_In_ WDFCOLLECTION _In_ ULONG Index

Referenced by Test_AllocLargeScaled(), Test_AllocLargeUnscaled(), Test_AllocSmall(), Test_ChainedInfo(), Test_ContextPointers(), Test_Epilog(), Test_PartialProlog(), Test_PushMachframe(), Test_PushNonvol(), Test_SaveNonvol(), Test_SaveNonvolFar(), Test_SaveXmm128(), Test_SaveXmm128Far(), Test_SetFpReg(), Test_SpareCode(), and Test_TypicalProlog().

◆ START_TEST()

START_TEST ( RtlVirtualUnwind  )

Definition at line 534 of file RtlVirtualUnwind.c.

535{
550 Test_Epilog();
552}
static VOID Test_TypicalProlog(VOID)
static VOID Test_SaveXmm128(VOID)
static VOID Test_PushNonvol(VOID)
static VOID Test_PartialProlog(VOID)
static VOID Test_PushMachframe(VOID)
static VOID Test_ContextPointers(VOID)
static VOID Test_Epilog(VOID)
static VOID Test_AllocLargeScaled(VOID)
static VOID Test_AllocSmall(VOID)
static VOID Test_SaveXmm128Far(VOID)
static VOID Test_SpareCode(VOID)
static VOID Test_SaveNonvolFar(VOID)
static VOID Test_ChainedInfo(VOID)
static VOID Test_SetFpReg(VOID)
static VOID Test_AllocLargeUnscaled(VOID)
static VOID Test_SaveNonvol(VOID)

◆ Test_AllocLargeScaled()

static VOID Test_AllocLargeScaled ( VOID  )
static

Definition at line 176 of file RtlVirtualUnwind.c.

177{
178 CONTEXT Ctx;
180 ULONG_PTR Stack = (ULONG_PTR)g_StackBuffer;
181
182 RtlZeroMemory(g_StackBuffer, sizeof(g_StackBuffer));
183 g_StackBuffer[0x100 / 8] = 0x12345678ABCDEF00ULL;
184
185 /* sub rsp, 0x100 with ALLOC_LARGE OpInfo=0: next slot * 8 */
186 Info = ResetUnwindInfo(1, 7, 2);
187 SetCode(Info, 0, 7, UWOP_ALLOC_LARGE, 0);
188 Info->UnwindCode[1].FrameOffset = 0x100 / 8;
189
190 ok_eq_hex64(RunUnwind(&Ctx, Stack, 7, NULL), Stack);
191 ok_eq_hex64(Ctx.Rip, 0x12345678ABCDEF00ULL);
192 ok_eq_hex64(Ctx.Rsp, Stack + 0x100 + 8);
193}
static VOID SetCode(TEST_UNWIND_INFO *Info, ULONG Index, UCHAR CodeOffset, UCHAR UnwindOp, UCHAR OpInfo)
#define UWOP_ALLOC_LARGE
static ULONG_PTR RunUnwind(PCONTEXT Context, ULONG_PTR Rsp, ULONG CodeOffset, PKNONVOLATILE_CONTEXT_POINTERS Pointers)
#define ok_eq_hex64(value, expected)
Definition: apitest.h:146
#define ULONG_PTR
Definition: config.h:101
_In_ WDFREQUEST _In_ PIO_STACK_LOCATION Stack
Definition: wdfrequest.h:639

Referenced by START_TEST().

◆ Test_AllocLargeUnscaled()

static VOID Test_AllocLargeUnscaled ( VOID  )
static

Definition at line 195 of file RtlVirtualUnwind.c.

196{
197 CONTEXT Ctx;
199 ULONG_PTR Stack = (ULONG_PTR)g_StackBuffer;
200 ULONG Size = 0x300;
201
202 RtlZeroMemory(g_StackBuffer, sizeof(g_StackBuffer));
203 g_StackBuffer[Size / 8] = 0xAA55AA55AA55AA55ULL;
204
205 /* sub rsp, Size with ALLOC_LARGE OpInfo=1: next 2 slots = full ULONG */
206 Info = ResetUnwindInfo(1, 7, 3);
207 SetCode(Info, 0, 7, UWOP_ALLOC_LARGE, 1);
208 *(ULONG *)&Info->UnwindCode[1] = Size;
209
210 ok_eq_hex64(RunUnwind(&Ctx, Stack, 7, NULL), Stack);
211 ok_eq_hex64(Ctx.Rip, 0xAA55AA55AA55AA55ULL);
212 ok_eq_hex64(Ctx.Rsp, Stack + Size + 8);
213}
uint32_t ULONG
Definition: typedefs.h:59
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4539

Referenced by START_TEST().

◆ Test_AllocSmall()

static VOID Test_AllocSmall ( VOID  )
static

Definition at line 158 of file RtlVirtualUnwind.c.

159{
160 CONTEXT Ctx;
162 ULONG_PTR Stack = (ULONG_PTR)g_StackBuffer;
163
164 RtlZeroMemory(g_StackBuffer, sizeof(g_StackBuffer));
165 g_StackBuffer[8] = 0xFEEDFACEFEEDFACEULL;
166
167 /* sub rsp, 0x40 -> OpInfo = (0x40/8) - 1 = 7 */
168 Info = ResetUnwindInfo(1, 4, 1);
169 SetCode(Info, 0, 4, UWOP_ALLOC_SMALL, 7);
170
171 ok_eq_hex64(RunUnwind(&Ctx, Stack, 4, NULL), Stack);
172 ok_eq_hex64(Ctx.Rip, 0xFEEDFACEFEEDFACEULL);
173 ok_eq_hex64(Ctx.Rsp, Stack + 0x40 + 8);
174}
#define UWOP_ALLOC_SMALL

Referenced by START_TEST().

◆ Test_ChainedInfo()

static VOID Test_ChainedInfo ( VOID  )
static

Definition at line 383 of file RtlVirtualUnwind.c.

384{
385 CONTEXT Ctx;
387 PRUNTIME_FUNCTION ParentFunc;
388 ULONG_PTR Stack = (ULONG_PTR)g_StackBuffer;
389
390 /* Child runs PUSH_NONVOL(RBX), then chains to a parent that runs
391 * PUSH_NONVOL(RBP). Final tail step pops Rip. */
392 RtlZeroMemory(g_StackBuffer, sizeof(g_StackBuffer));
393 g_StackBuffer[0] = 0xAA00AA00AA00AA00ULL; /* saved RBX */
394 g_StackBuffer[1] = 0xBB00BB00BB00BB00ULL; /* saved RBP */
395 g_StackBuffer[2] = 0xCC00CC00CC00CC00ULL; /* return Rip */
396
397 Child = ResetUnwindInfo(1, 1, 1);
398 Child->Flags = UNW_FLAG_CHAININFO;
400
401 /* Parent's RUNTIME_FUNCTION sits right after the rounded-up child
402 * UnwindCode array, at &UnwindCode[(CountOfCodes + 1) & ~1]. */
403 ParentFunc = (PRUNTIME_FUNCTION)&Child->UnwindCode[2];
404 ParentFunc->BeginAddress = FIELD_OFFSET(IMAGE_STRUCT, Code);
405 ParentFunc->EndAddress = FIELD_OFFSET(IMAGE_STRUCT, Data);
406 ParentFunc->UnwindData = FIELD_OFFSET(IMAGE_STRUCT, Unwind) + PARENT_OFFSET;
407
408 Parent = (TEST_UNWIND_INFO *)(g_Image.Unwind + PARENT_OFFSET);
409 RtlZeroMemory(Parent, sizeof(*Parent));
410 Parent->Version = 1;
411 Parent->SizeOfProlog = 1;
412 Parent->CountOfCodes = 1;
414
415 RunUnwind(&Ctx, Stack, 1, NULL);
416 ok_eq_hex64(Ctx.Rbx, 0xAA00AA00AA00AA00ULL);
417 ok_eq_hex64(Ctx.Rbp, 0xBB00BB00BB00BB00ULL);
418 ok_eq_hex64(Ctx.Rip, 0xCC00CC00CC00CC00ULL);
419 ok_eq_hex64(Ctx.Rsp, Stack + 0x18);
420}
#define PARENT_OFFSET
#define UWOP_PUSH_NONVOL
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 Parent
Definition: acpixf.h:732
static PRUNTIME_FUNCTION(WINAPI *pRtlLookupFunctionEntry)(ULONG_PTR
_Must_inspect_result_ _In_ WDFDEVICE _In_ WDFDEVICE Child
Definition: wdffdo.h:536

Referenced by START_TEST().

◆ Test_ContextPointers()

static VOID Test_ContextPointers ( VOID  )
static

Definition at line 364 of file RtlVirtualUnwind.c.

365{
366 CONTEXT Ctx;
367 KNONVOLATILE_CONTEXT_POINTERS Ptrs;
369 ULONG_PTR Stack = (ULONG_PTR)g_StackBuffer;
370
371 RtlZeroMemory(g_StackBuffer, sizeof(g_StackBuffer));
372 RtlZeroMemory(&Ptrs, sizeof(Ptrs));
373 g_StackBuffer[0] = 0xAABBCCDDAABBCCDDULL;
374
375 Info = ResetUnwindInfo(1, 1, 1);
377
378 RunUnwind(&Ctx, Stack, 1, &Ptrs);
379 ok_eq_pointer(Ptrs.Rbx, &g_StackBuffer[0]);
380 ok_eq_hex64(Ctx.Rbx, 0xAABBCCDDAABBCCDDULL);
381}
#define ok_eq_pointer(value, expected)
Definition: apitest.h:116

Referenced by START_TEST().

◆ Test_Epilog()

static VOID Test_Epilog ( VOID  )
static

Definition at line 478 of file RtlVirtualUnwind.c.

479{
480 CONTEXT Ctx;
482 ULONG_PTR Stack = (ULONG_PTR)g_StackBuffer;
483
484 /* UWOP_EPILOG consumes 2 slots. If the unwinder advances by only 1,
485 * the trailing zero slot is misread as UWOP_PUSH_NONVOL(RAX) and the
486 * subsequent PUSH_NONVOL(RDI) sees a shifted Rsp. */
487 RtlZeroMemory(g_StackBuffer, sizeof(g_StackBuffer));
488 g_StackBuffer[0] = 0xAAAAAAAAAAAAAAAAULL;
489 g_StackBuffer[1] = 0xBBBBBBBBBBBBBBBBULL;
490
491 Info = ResetUnwindInfo(2, 0, 3);
492 SetCode(Info, 0, 0, UWOP_EPILOG, 0);
493 Info->UnwindCode[1].FrameOffset = 0;
495
496 RunUnwind(&Ctx, Stack, 0, NULL);
497 ok_eq_hex64(Ctx.Rdi, 0xAAAAAAAAAAAAAAAAULL);
498 ok_eq_hex64(Ctx.Rax, INIT_RAX);
499}
#define UWOP_EPILOG

Referenced by START_TEST().

◆ Test_PartialProlog()

static VOID Test_PartialProlog ( VOID  )
static

Definition at line 337 of file RtlVirtualUnwind.c.

338{
339 CONTEXT Ctx;
341 ULONG_PTR Stack = (ULONG_PTR)g_StackBuffer;
342
343 /* Same prolog but ControlPc is between push rbx and sub rsp.
344 * Only push rbp / push rbx have executed, so sub rsp must NOT undo. */
345 RtlZeroMemory(g_StackBuffer, sizeof(g_StackBuffer));
346 g_StackBuffer[0] = 0x2222222222222222ULL;
347 g_StackBuffer[1] = 0x3333333333333333ULL;
348 g_StackBuffer[2] = 0x4444444444444444ULL;
349
350 Info = ResetUnwindInfo(1, 7, 4);
351 SetCode(Info, 0, 7, UWOP_ALLOC_SMALL, 7);
355
356 ok_eq_hex64(RunUnwind(&Ctx, Stack, 2, NULL), Stack);
357 ok_eq_hex64(Ctx.Rbx, 0x2222222222222222ULL);
358 ok_eq_hex64(Ctx.Rbp, 0x3333333333333333ULL);
359 ok_eq_hex64(Ctx.Rip, 0x4444444444444444ULL);
360 ok_eq_hex64(Ctx.Rsi, 0); /* push rsi not yet executed */
361 ok_eq_hex64(Ctx.Rsp, Stack + 0x18);
362}

Referenced by START_TEST().

◆ Test_PushMachframe()

static VOID Test_PushMachframe ( VOID  )
static

Definition at line 284 of file RtlVirtualUnwind.c.

285{
286 CONTEXT Ctx;
288 ULONG_PTR Stack = (ULONG_PTR)g_StackBuffer;
289
290 /* MACHINE_FRAME layout: [Rip][Cs][EFlags][Rsp][Ss], OpInfo=1 means an
291 * error code was pushed (one extra QWORD before the frame). */
292 RtlZeroMemory(g_StackBuffer, sizeof(g_StackBuffer));
293 g_StackBuffer[1] = 0xCAFEBABE00000000ULL; /* Rip */
294 g_StackBuffer[4] = Stack + 0x100; /* Rsp */
295
296 Info = ResetUnwindInfo(1, 1, 1);
298
299 RunUnwind(&Ctx, Stack, 1, NULL);
300 ok_eq_hex64(Ctx.Rip, 0xCAFEBABE00000000ULL);
301 ok_eq_hex64(Ctx.Rsp, Stack + 0x100);
302}
#define UWOP_PUSH_MACHFRAME

Referenced by START_TEST().

◆ Test_PushNonvol()

static VOID Test_PushNonvol ( VOID  )
static

Definition at line 139 of file RtlVirtualUnwind.c.

140{
141 CONTEXT Ctx;
143 ULONG_PTR Stack = (ULONG_PTR)g_StackBuffer;
144
145 RtlZeroMemory(g_StackBuffer, sizeof(g_StackBuffer));
146 g_StackBuffer[0] = 0x1111111122222222ULL;
147 g_StackBuffer[1] = 0xDEADC0DEDEADC0DEULL;
148
149 Info = ResetUnwindInfo(1, 1, 1);
151
152 ok_eq_hex64(RunUnwind(&Ctx, Stack, 1, NULL), Stack);
153 ok_eq_hex64(Ctx.Rbp, 0x1111111122222222ULL);
154 ok_eq_hex64(Ctx.Rip, 0xDEADC0DEDEADC0DEULL);
155 ok_eq_hex64(Ctx.Rsp, Stack + 16);
156}

Referenced by START_TEST().

◆ Test_SaveNonvol()

static VOID Test_SaveNonvol ( VOID  )
static

Definition at line 241 of file RtlVirtualUnwind.c.

242{
243 CONTEXT Ctx;
245 ULONG_PTR Stack = (ULONG_PTR)g_StackBuffer;
246
247 RtlZeroMemory(g_StackBuffer, sizeof(g_StackBuffer));
248 g_StackBuffer[0x80 / 8] = 0x4242424242424242ULL;
249 g_StackBuffer[0] = 0xDEADC0DEDEADC0DEULL;
250
251 /* mov [rsp + 0x80], rsi; FrameOffset (in 8-byte units) = 0x10 */
252 Info = ResetUnwindInfo(1, 8, 2);
254 Info->UnwindCode[1].FrameOffset = 0x10;
255
256 ok_eq_hex64(RunUnwind(&Ctx, Stack, 8, NULL), Stack);
257 ok_eq_hex64(Ctx.Rsi, 0x4242424242424242ULL);
258 ok_eq_hex64(Ctx.Rip, 0xDEADC0DEDEADC0DEULL);
259 ok_eq_hex64(Ctx.Rsp, Stack + 8);
260}
#define UWOP_SAVE_NONVOL

Referenced by START_TEST().

◆ Test_SaveNonvolFar()

static VOID Test_SaveNonvolFar ( VOID  )
static

Definition at line 422 of file RtlVirtualUnwind.c.

423{
424 CONTEXT Ctx;
426 ULONG_PTR Stack = (ULONG_PTR)g_StackBuffer;
427
428 /* Expected at unscaled byte offset 8, decoy at the buggy
429 * (DWORD64*)Rsp + 8 == Rsp + 64 location. */
430 RtlZeroMemory(g_StackBuffer, sizeof(g_StackBuffer));
431 g_StackBuffer[1] = 0xAAAAAAAABBBBBBBBULL; /* byte offset 8 */
432 g_StackBuffer[8] = 0xCCCCCCCCDDDDDDDDULL; /* byte offset 64 */
433
434 Info = ResetUnwindInfo(2, 0, 3);
436 *(ULONG *)&Info->UnwindCode[1] = 8;
437
438 RunUnwind(&Ctx, Stack, 0, NULL);
439 ok_eq_hex64(Ctx.Rbx, 0xAAAAAAAABBBBBBBBULL);
440 ok(Ctx.Rbx != 0xCCCCCCCCDDDDDDDDULL,
441 "Rbx looks scaled-by-8: %I64x\n", Ctx.Rbx);
442 /* If the unwinder mis-advances i, trailing zero slots decode as
443 * UWOP_PUSH_NONVOL(RAX) and shift Rsp / clobber Rax. */
444 ok_eq_hex64(Ctx.Rax, INIT_RAX);
445 ok_eq_hex64(Ctx.Rsp, Stack + 8);
446}
#define UWOP_SAVE_NONVOL_FAR
#define ok(value,...)
Definition: atltest.h:57

Referenced by START_TEST().

◆ Test_SaveXmm128()

static VOID Test_SaveXmm128 ( VOID  )
static

Definition at line 262 of file RtlVirtualUnwind.c.

263{
264 CONTEXT Ctx;
266 ULONG_PTR Stack = (ULONG_PTR)g_StackBuffer;
268
269 Expected.Low = 0x0011223344556677ULL;
270 Expected.High = 0x8899AABBCCDDEEFFULL;
271
272 RtlZeroMemory(g_StackBuffer, sizeof(g_StackBuffer));
273 *(M128A *)&g_StackBuffer[0x40 / 8] = Expected;
274
275 /* movaps [rsp + 0x40], xmm7; FrameOffset (in 16-byte units) = 4 */
276 Info = ResetUnwindInfo(1, 9, 2);
277 SetCode(Info, 0, 9, UWOP_SAVE_XMM128, 7 /* XMM7 */);
278 Info->UnwindCode[1].FrameOffset = 4;
279
280 ok_eq_hex64(RunUnwind(&Ctx, Stack, 9, NULL), Stack);
281 ok_eq_xmm(Ctx.Xmm7, Expected);
282}
BOOLEAN Expected
#define UWOP_SAVE_XMM128
#define ok_eq_xmm(value, expected)
Definition: apitest.h:147
M128A
Definition: ketypes.h:992

Referenced by START_TEST().

◆ Test_SaveXmm128Far()

static VOID Test_SaveXmm128Far ( VOID  )
static

Definition at line 448 of file RtlVirtualUnwind.c.

449{
450 CONTEXT Ctx;
452 ULONG_PTR Stack = (ULONG_PTR)g_StackBuffer;
453 M128A Expected, Decoy;
454
455 Expected.Low = 0x1111111122222222ULL;
456 Expected.High = 0x3333333344444444ULL;
457 Decoy.Low = 0x5555555566666666ULL;
458 Decoy.High = 0x7777777788888888ULL;
459
460 /* Expected at unscaled byte offset 16, decoy at the buggy
461 * (M128A*)Rsp + 16 == Rsp + 256 location. */
462 RtlZeroMemory(g_StackBuffer, sizeof(g_StackBuffer));
463 *(M128A *)&g_StackBuffer[16 / 8] = Expected;
464 *(M128A *)&g_StackBuffer[256 / 8] = Decoy;
465
466 Info = ResetUnwindInfo(2, 0, 3);
467 SetCode(Info, 0, 0, UWOP_SAVE_XMM128_FAR, 6 /* XMM6 */);
468 *(ULONG *)&Info->UnwindCode[1] = 16;
469
470 RunUnwind(&Ctx, Stack, 0, NULL);
471 ok_eq_xmm(Ctx.Xmm6, Expected);
472 ok(Ctx.Xmm6.Low != Decoy.Low,
473 "Xmm6 looks scaled-by-16: %I64x\n", Ctx.Xmm6.Low);
474 ok_eq_hex64(Ctx.Rax, INIT_RAX);
475 ok_eq_hex64(Ctx.Rsp, Stack + 8);
476}
#define UWOP_SAVE_XMM128_FAR

Referenced by START_TEST().

◆ Test_SetFpReg()

static VOID Test_SetFpReg ( VOID  )
static

Definition at line 215 of file RtlVirtualUnwind.c.

216{
217 CONTEXT Ctx;
219 ULONG_PTR EstFrame;
220 ULONG_PTR Stack = (ULONG_PTR)g_StackBuffer;
221 ULONG_PTR FrameTop = Stack + 0x100;
222
223 /* lea rbp, [rsp + 0x20]; FrameOffset (in 16-byte units) = 2 */
224 RtlZeroMemory(g_StackBuffer, sizeof(g_StackBuffer));
225 g_StackBuffer[0x100 / 8] = 0x9999AAAA9999AAAAULL;
226
227 Info = ResetUnwindInfo(1, 4, 1);
228 Info->FrameRegister = REG_RBP;
229 Info->FrameOffset = 2;
230 SetCode(Info, 0, 4, UWOP_SET_FPREG, 0);
231
232 InitContext(&Ctx, Stack);
233 Ctx.Rbp = FrameTop + 0x20;
234 EstFrame = DoUnwind(&Ctx, 4, NULL);
235
236 ok_eq_hex64(EstFrame, FrameTop);
237 ok_eq_hex64(Ctx.Rip, 0x9999AAAA9999AAAAULL);
238 ok_eq_hex64(Ctx.Rsp, FrameTop + 8);
239}
#define UWOP_SET_FPREG

Referenced by START_TEST().

◆ Test_SpareCode()

static VOID Test_SpareCode ( VOID  )
static

Definition at line 501 of file RtlVirtualUnwind.c.

502{
503 CONTEXT Ctx;
505 ULONG_PTR Stack = (ULONG_PTR)g_StackBuffer;
506
507 /* Same idea as Test_Epilog, but UWOP_SPARE_CODE consumes 3 slots.
508 * The unwinder hits ASSERT(FALSE) before advancing i, so on debug
509 * (DBG=1) builds the fix path is unreachable; catch and skip. */
510 RtlZeroMemory(g_StackBuffer, sizeof(g_StackBuffer));
511 g_StackBuffer[0] = 0xAAAAAAAAAAAAAAAAULL;
512 g_StackBuffer[1] = 0xBBBBBBBBBBBBBBBBULL;
513
514 Info = ResetUnwindInfo(2, 0, 4);
515 SetCode(Info, 0, 0, UWOP_SPARE_CODE, 0);
516 Info->UnwindCode[1].FrameOffset = 0;
517 Info->UnwindCode[2].FrameOffset = 0;
519
521 {
522 RunUnwind(&Ctx, Stack, 0, NULL);
523 ok_eq_hex64(Ctx.Rdi, 0xAAAAAAAAAAAAAAAAULL);
524 ok_eq_hex64(Ctx.Rax, INIT_RAX);
525 }
527 {
528 skip("UWOP_SPARE_CODE triggered exception 0x%08lx (debug build ASSERT)\n",
530 }
531 _SEH2_END;
532}
#define UWOP_SPARE_CODE
#define skip(...)
Definition: atltest.h:64
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
#define _SEH2_GetExceptionCode()
Definition: pseh2_64.h:204
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:104
#define _SEH2_END
Definition: pseh2_64.h:194
#define _SEH2_TRY
Definition: pseh2_64.h:93

Referenced by START_TEST().

◆ Test_TypicalProlog()

static VOID Test_TypicalProlog ( VOID  )
static

Definition at line 304 of file RtlVirtualUnwind.c.

305{
306 CONTEXT Ctx;
308 ULONG_PTR Stack = (ULONG_PTR)g_StackBuffer;
309
310 /* Equivalent to:
311 * push rbp ; CodeOffset 1
312 * push rbx ; CodeOffset 2
313 * push rsi ; CodeOffset 3
314 * sub rsp, 0x40 ; CodeOffset 7 (4-byte instruction)
315 */
316 RtlZeroMemory(g_StackBuffer, sizeof(g_StackBuffer));
317 g_StackBuffer[0x40 / 8] = 0x1111111111111111ULL; /* saved RSI */
318 g_StackBuffer[0x48 / 8] = 0x2222222222222222ULL; /* saved RBX */
319 g_StackBuffer[0x50 / 8] = 0x3333333333333333ULL; /* saved RBP */
320 g_StackBuffer[0x58 / 8] = 0x4444444444444444ULL; /* return Rip */
321
322 Info = ResetUnwindInfo(1, 7, 4);
323 SetCode(Info, 0, 7, UWOP_ALLOC_SMALL, 7);
327
328 ok_eq_hex64(RunUnwind(&Ctx, Stack, 7, NULL), Stack);
329 ok_eq_hex64(Ctx.Rsi, 0x1111111111111111ULL);
330 ok_eq_hex64(Ctx.Rbx, 0x2222222222222222ULL);
331 ok_eq_hex64(Ctx.Rbp, 0x3333333333333333ULL);
332 ok_eq_hex64(Ctx.Rip, 0x4444444444444444ULL);
333 ok_eq_hex64(Ctx.Rsp, Stack + 0x60);
334 ok_eq_hex64(Ctx.Rax, INIT_RAX);
335}

Referenced by START_TEST().