ReactOS 0.4.16-dev-1946-g52006dd
unwind.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS runtime library
3 * LICENSE: MIT (https://spdx.org/licenses/MIT)
4 * PURPOSE: Unwinding related functions
5 * COPYRIGHT: Copyright 2010-2025 Timo Kreuzer <timo.kreuzer@reactos.org>
6 */
7
8/* INCLUDES *****************************************************************/
9
10#include <rtl.h>
11
12#define NDEBUG
13#include <debug.h>
14
15#define UNWIND_HISTORY_TABLE_NONE 0
16#define UNWIND_HISTORY_TABLE_GLOBAL 1
17#define UNWIND_HISTORY_TABLE_LOCAL 2
18
19#define UWOP_PUSH_NONVOL 0
20#define UWOP_ALLOC_LARGE 1
21#define UWOP_ALLOC_SMALL 2
22#define UWOP_SET_FPREG 3
23#define UWOP_SAVE_NONVOL 4
24#define UWOP_SAVE_NONVOL_FAR 5
25#if 0 // These are deprecated / not for x64
26#define UWOP_SAVE_XMM 6
27#define UWOP_SAVE_XMM_FAR 7
28#else
29#define UWOP_EPILOG 6
30#define UWOP_SPARE_CODE 7
31#endif
32#define UWOP_SAVE_XMM128 8
33#define UWOP_SAVE_XMM128_FAR 9
34#define UWOP_PUSH_MACHFRAME 10
35
36
37typedef unsigned char UBYTE;
38
39typedef union _UNWIND_CODE
40{
41 struct
42 {
46 };
49
50typedef struct _UNWIND_INFO
51{
59/* union {
60 OPTIONAL ULONG ExceptionHandler;
61 OPTIONAL ULONG FunctionEntry;
62 };
63 OPTIONAL ULONG ExceptionData[];
64*/
66
67/* FUNCTIONS *****************************************************************/
68
80PRUNTIME_FUNCTION
83 IN DWORD64 ControlPc,
84 OUT PDWORD64 ImageBase,
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}
109
110PRUNTIME_FUNCTION
111NTAPI
113 _In_ DWORD64 ControlPc,
114 _Out_ PDWORD64 ImageBase,
115 _In_ PUNWIND_HISTORY_TABLE HistoryTable);
116
122PRUNTIME_FUNCTION
123NTAPI
125 IN DWORD64 ControlPc,
126 OUT PDWORD64 ImageBase,
127 OUT PUNWIND_HISTORY_TABLE HistoryTable)
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}
173
174static
176ULONG
178 _In_ UNWIND_CODE UnwindCode)
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}
206
207static
209void
212 _In_ BYTE Reg,
214{
215 ((DWORD64*)(&Context->Rax))[Reg] = Value;
216}
217
218static
220void
223 _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers,
224 _In_ BYTE Reg,
225 _In_ PDWORD64 ValuePointer)
226{
227 SetReg(Context, Reg, *ValuePointer);
228 if (ContextPointers != NULL)
229 {
230 ContextPointers->IntegerContext[Reg] = ValuePointer;
231 }
232}
233
234static
239 _In_ BYTE Reg)
240{
241 return ((DWORD64*)(&Context->Rax))[Reg];
242}
243
244static
246void
249 _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers,
250 _In_ BYTE Reg)
251{
252 SetRegFromStackValue(Context, ContextPointers, Reg, (PDWORD64)Context->Rsp);
253 Context->Rsp += sizeof(DWORD64);
254}
255
256static
258void
261 _In_ BYTE Reg,
263{
264 ((M128A*)(&Context->Xmm0))[Reg] = Value;
265}
266
267static
269void
272 _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers,
273 _In_ BYTE Reg,
274 _In_ M128A *ValuePointer)
275{
276 SetXmmReg(Context, Reg, *ValuePointer);
277 if (ContextPointers != NULL)
278 {
279 ContextPointers->FloatingContext[Reg] = ValuePointer;
280 }
281}
282
283static
285M128A
287{
288 return ((M128A*)(&Context->Xmm0))[Reg];
289}
290
301static
306 _In_ ULONG64 ControlPc,
307 _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers,
308 _In_ ULONG64 ImageBase,
309 _In_ PRUNTIME_FUNCTION FunctionEntry)
310{
311 CONTEXT LocalContext;
312 BYTE *InstrPtr;
313 DWORD Instr;
314 BYTE Reg, Mod;
315 ULONG64 EndAddress;
316
317 /* Make a local copy of the context */
318 LocalContext = *Context;
319
320 InstrPtr = (BYTE*)ControlPc;
321
322 /* Check if first instruction of epilog is "add rsp, x" */
323 Instr = *(DWORD*)InstrPtr;
324 if ( (Instr & 0x00fffdff) == 0x00c48148 )
325 {
326 if ( (Instr & 0x0000ff00) == 0x8300 )
327 {
328 /* This is "add rsp, 0x??" */
329 LocalContext.Rsp += Instr >> 24;
330 InstrPtr += 4;
331 }
332 else
333 {
334 /* This is "add rsp, 0x???????? */
335 LocalContext.Rsp += *(DWORD*)(InstrPtr + 3);
336 InstrPtr += 7;
337 }
338 }
339 /* Check if first instruction of epilog is "lea rsp, ..." */
340 else if ( (Instr & 0x38fffe) == 0x208d48 )
341 {
342 /* Get the register */
343 Reg = (Instr >> 16) & 0x7;
344
345 /* REX.R */
346 Reg += (Instr & 1) * 8;
347
348 LocalContext.Rsp = GetReg(&LocalContext, Reg);
349
350 /* Get addressing mode */
351 Mod = (Instr >> 22) & 0x3;
352 if (Mod == 0)
353 {
354 /* No displacement */
355 InstrPtr += 3;
356 }
357 else if (Mod == 1)
358 {
359 /* 1 byte displacement */
360 LocalContext.Rsp += (LONG)(CHAR)(Instr >> 24);
361 InstrPtr += 4;
362 }
363 else if (Mod == 2)
364 {
365 /* 4 bytes displacement */
366 LocalContext.Rsp += *(LONG*)(InstrPtr + 3);
367 InstrPtr += 7;
368 }
369 }
370
371 /* Loop the following instructions before the ret */
372 EndAddress = FunctionEntry->EndAddress + ImageBase - 1;
373 while ((DWORD64)InstrPtr < EndAddress)
374 {
375 Instr = *(DWORD*)InstrPtr;
376
377 /* Check for a simple pop */
378 if ( (Instr & 0xf8) == 0x58 )
379 {
380 /* Opcode pops a basic register from stack */
381 Reg = Instr & 0x7;
382 PopReg(&LocalContext, ContextPointers, Reg);
383 InstrPtr++;
384 continue;
385 }
386
387 /* Check for REX + pop */
388 if ( (Instr & 0xf8fb) == 0x5841 )
389 {
390 /* Opcode is pop r8 .. r15 */
391 Reg = ((Instr >> 8) & 0x7) + 8;
392 PopReg(&LocalContext, ContextPointers, Reg);
393 InstrPtr += 2;
394 continue;
395 }
396
397 /* Opcode not allowed for Epilog */
398 return FALSE;
399 }
400
401 // check for popfq
402
403 // also allow end with jmp imm, jmp [target], iretq
404
405 /* Check if we are at the ret instruction */
406 if ((DWORD64)InstrPtr != EndAddress)
407 {
408 /* If we went past the end of the function, something is broken! */
409 ASSERT((DWORD64)InstrPtr <= EndAddress);
410 return FALSE;
411 }
412
413 /* Make sure this is really a ret instruction */
414 if (*InstrPtr != 0xc3)
415 {
416 return FALSE;
417 }
418
419 /* Unwind is finished, pop new Rip from Stack */
420 LocalContext.Rip = *(DWORD64*)LocalContext.Rsp;
421 LocalContext.Rsp += sizeof(DWORD64);
422
423 *Context = LocalContext;
424 return TRUE;
425}
426
431static
435 _In_ PUNWIND_INFO UnwindInfo,
436 _In_ ULONG_PTR CodeOffset)
437{
438 ULONG i;
439
440 /* Check if we have a frame register */
441 if (UnwindInfo->FrameRegister == 0)
442 {
443 /* No frame register means we use Rsp */
444 return Context->Rsp;
445 }
446
447 if ((CodeOffset >= UnwindInfo->SizeOfProlog) ||
448 ((UnwindInfo->Flags & UNW_FLAG_CHAININFO) != 0))
449 {
450 return GetReg(Context, UnwindInfo->FrameRegister) -
451 UnwindInfo->FrameOffset * 16;
452 }
453
454 /* Loop all unwind ops */
455 for (i = 0;
456 i < UnwindInfo->CountOfCodes;
457 i += UnwindOpSlots(UnwindInfo->UnwindCode[i]))
458 {
459 /* Skip codes past our code offset */
460 if (UnwindInfo->UnwindCode[i].CodeOffset > CodeOffset)
461 {
462 continue;
463 }
464
465 /* Check for SET_FPREG */
466 if (UnwindInfo->UnwindCode[i].UnwindOp == UWOP_SET_FPREG)
467 {
468 return GetReg(Context, UnwindInfo->FrameRegister) -
469 UnwindInfo->FrameOffset * 16;
470 }
471 }
472
473 return Context->Rsp;
474}
475
477NTAPI
480 _In_ ULONG64 ImageBase,
481 _In_ ULONG64 ControlPc,
482 _In_ PRUNTIME_FUNCTION FunctionEntry,
484 _Outptr_ PVOID *HandlerData,
486 _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers)
487{
488 PUNWIND_INFO UnwindInfo;
489 ULONG_PTR ControlRva, CodeOffset;
490 ULONG i, Offset;
491 UNWIND_CODE UnwindCode;
492 BYTE Reg;
493 PULONG LanguageHandler;
494
495 /* Get relative virtual address */
496 ControlRva = ControlPc - ImageBase;
497
498 /* Sanity checks */
499 if ( (ControlRva < FunctionEntry->BeginAddress) ||
500 (ControlRva >= FunctionEntry->EndAddress) )
501 {
502 return NULL;
503 }
504
505 /* Get a pointer to the unwind info */
506 UnwindInfo = RVA(ImageBase, FunctionEntry->UnwindData);
507
508 /* The language specific handler data follows the unwind info */
509 LanguageHandler = ALIGN_UP_POINTER_BY(&UnwindInfo->UnwindCode[UnwindInfo->CountOfCodes], sizeof(ULONG));
510
511 /* Calculate relative offset to function start */
512 CodeOffset = ControlRva - FunctionEntry->BeginAddress;
513
514 *EstablisherFrame = GetEstablisherFrame(Context, UnwindInfo, CodeOffset);
515
516 /* Check if we are in the function epilog and try to finish it */
517 if ((CodeOffset > UnwindInfo->SizeOfProlog) && (UnwindInfo->CountOfCodes > 0))
518 {
519 if (RtlpTryToUnwindEpilog(Context, ControlPc, ContextPointers, ImageBase, FunctionEntry))
520 {
521 /* There's no exception routine */
522 return NULL;
523 }
524 }
525
526 /* Skip all Ops with an offset greater than the current Offset */
527 i = 0;
528 while ((i < UnwindInfo->CountOfCodes) &&
529 (UnwindInfo->UnwindCode[i].CodeOffset > CodeOffset))
530 {
531 i += UnwindOpSlots(UnwindInfo->UnwindCode[i]);
532 }
533
534RepeatChainedInfo:
535
536 /* Process the remaining unwind ops */
537 while (i < UnwindInfo->CountOfCodes)
538 {
539 UnwindCode = UnwindInfo->UnwindCode[i];
540 switch (UnwindCode.UnwindOp)
541 {
542 case UWOP_PUSH_NONVOL:
543 Reg = UnwindCode.OpInfo;
544 PopReg(Context, ContextPointers, Reg);
545 i++;
546 break;
547
548 case UWOP_ALLOC_LARGE:
549 if (UnwindCode.OpInfo)
550 {
551 Offset = *(ULONG*)(&UnwindInfo->UnwindCode[i+1]);
552 Context->Rsp += Offset;
553 i += 3;
554 }
555 else
556 {
557 Offset = UnwindInfo->UnwindCode[i+1].FrameOffset;
558 Context->Rsp += Offset * 8;
559 i += 2;
560 }
561 break;
562
563 case UWOP_ALLOC_SMALL:
564 Context->Rsp += (UnwindCode.OpInfo + 1) * 8;
565 i++;
566 break;
567
568 case UWOP_SET_FPREG:
569 Reg = UnwindInfo->FrameRegister;
570 Context->Rsp = GetReg(Context, Reg) - UnwindInfo->FrameOffset * 16;
571 i++;
572 break;
573
574 case UWOP_SAVE_NONVOL:
575 Reg = UnwindCode.OpInfo;
576 Offset = UnwindInfo->UnwindCode[i + 1].FrameOffset;
577 SetRegFromStackValue(Context, ContextPointers, Reg, (DWORD64*)Context->Rsp + Offset);
578 i += 2;
579 break;
580
582 Reg = UnwindCode.OpInfo;
583 Offset = *(ULONG*)(&UnwindInfo->UnwindCode[i + 1]);
584 SetRegFromStackValue(Context, ContextPointers, Reg, (DWORD64*)Context->Rsp + Offset);
585 i += 3;
586 break;
587
588 case UWOP_EPILOG:
589 i += 1;
590 break;
591
592 case UWOP_SPARE_CODE:
593 ASSERT(FALSE);
594 i += 2;
595 break;
596
597 case UWOP_SAVE_XMM128:
598 Reg = UnwindCode.OpInfo;
599 Offset = UnwindInfo->UnwindCode[i + 1].FrameOffset;
600 SetXmmRegFromStackValue(Context, ContextPointers, Reg, (M128A*)Context->Rsp + Offset);
601 i += 2;
602 break;
603
605 Reg = UnwindCode.OpInfo;
606 Offset = *(ULONG*)(&UnwindInfo->UnwindCode[i + 1]);
607 SetXmmRegFromStackValue(Context, ContextPointers, Reg, (M128A*)Context->Rsp + Offset);
608 i += 3;
609 break;
610
612 /* OpInfo is 1, when an error code was pushed, otherwise 0. */
613 Context->Rsp += UnwindCode.OpInfo * sizeof(DWORD64);
614
615 /* Now pop the MACHINE_FRAME (RIP/RSP only. And yes, "magic numbers", deal with it) */
616 Context->Rip = *(PDWORD64)(Context->Rsp + 0x00);
617 Context->Rsp = *(PDWORD64)(Context->Rsp + 0x18);
618 ASSERT((i + 1) == UnwindInfo->CountOfCodes);
619 goto Exit;
620 }
621 }
622
623 /* Check for chained info */
624 if (UnwindInfo->Flags & UNW_FLAG_CHAININFO)
625 {
626 /* See https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64?view=msvc-160#chained-unwind-info-structures */
627 FunctionEntry = (PRUNTIME_FUNCTION)&(UnwindInfo->UnwindCode[(UnwindInfo->CountOfCodes + 1) & ~1]);
628 UnwindInfo = RVA(ImageBase, FunctionEntry->UnwindData);
629 i = 0;
630 goto RepeatChainedInfo;
631 }
632
633 /* Unwind is finished, pop new Rip from Stack */
634 if (Context->Rsp != 0)
635 {
636 Context->Rip = *(DWORD64*)Context->Rsp;
637 Context->Rsp += sizeof(DWORD64);
638 }
639
640Exit:
641
642 /* Check if we have a handler and return it */
643 if (UnwindInfo->Flags & (HandlerType & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER)))
644 {
645 *HandlerData = (LanguageHandler + 1);
646 return RVA(ImageBase, *LanguageHandler);
647 }
648
649 return NULL;
650}
651
652static __inline
653BOOL
655 _In_ ULONG64 StackPointer,
656 _In_ ULONG64 LowLimit,
658{
659 return (StackPointer >= LowLimit) &&
660 (StackPointer < HighLimit) &&
661 ((StackPointer & 7) == 0);
662}
663
666 _Inout_ PEXCEPTION_RECORD ExceptionRecord,
670{
671 /* Get a pointer to the register home space for RtlpExecuteHandlerForUnwind */
672 PULONG64 HomeSpace = (PULONG64)EstablisherFrame + 6;
673
674 /* Get the ExceptionFlags value, which was saved in the home space */
675 ULONG ExceptionFlags = (ULONG)HomeSpace[0];
676
677 /* Get the DispatcherContext, which was saved in the home space */
678 PDISPATCHER_CONTEXT PreviousDispatcherContext = (PDISPATCHER_CONTEXT)HomeSpace[3];
679
680 /* Check if the original call to RtlpExecuteHandlerForUnwind was an unwind */
681 if (IS_UNWINDING(ExceptionFlags))
682 {
683 /* Check if the current call to this function is due to unwinding */
684 if (IS_UNWINDING(ExceptionRecord->ExceptionFlags))
685 {
686 /* We are unwinding over the call to a termination handler. This
687 could be due to an exception or longjmp. We need to make sure
688 to not run this termination handler again. To achieve that,
689 we copy the contents of the original dispatcher context back
690 over the current dispatcher context and return
691 ExceptionCollidedUnwind. RtlUnwindInternal will take the
692 original context, and continue unwing there. */
693 *DispatcherContext = *PreviousDispatcherContext;
695 }
696 }
697
698 // TODO: properly handle nested exceptions
699
701}
702
703
716NTAPI
718 _In_opt_ PVOID TargetFrame,
719 _In_opt_ PVOID TargetIp,
720 _In_ PEXCEPTION_RECORD ExceptionRecord,
723 _In_opt_ struct _UNWIND_HISTORY_TABLE *HistoryTable,
725{
727 PEXCEPTION_ROUTINE ExceptionRoutine;
729 PRUNTIME_FUNCTION FunctionEntry;
730 ULONG_PTR StackLow, StackHigh;
731 ULONG64 ImageBase, EstablisherFrame;
732 CONTEXT UnwindContext;
733
734 /* Get the current stack limits */
735 RtlpGetStackLimits(&StackLow, &StackHigh);
736
737 /* If we have a target frame, then this is our high limit */
738 if (TargetFrame != NULL)
739 {
740 StackHigh = (ULONG64)TargetFrame + 1;
741 }
742
743 /* Copy the context */
744 UnwindContext = *ContextRecord;
745
746 /* Set up the constant fields of the dispatcher context */
747 DispatcherContext.ContextRecord =
748 (HandlerType == UNW_FLAG_UHANDLER) ? ContextRecord : &UnwindContext;
749 DispatcherContext.HistoryTable = HistoryTable;
750 DispatcherContext.TargetIp = (ULONG64)TargetIp;
751
752 /* Start looping */
753 while (TRUE)
754 {
755 if (!RtlpIsStackPointerValid(UnwindContext.Rsp, StackLow, StackHigh))
756 {
757 return FALSE;
758 }
759
760 /* Lookup the FunctionEntry for the current RIP */
761 FunctionEntry = RtlLookupFunctionEntry(UnwindContext.Rip, &ImageBase, NULL);
762 if (FunctionEntry == NULL)
763 {
764 /* No function entry, so this must be a leaf function. Pop the return address from the stack.
765 Note: this can happen after the first frame as the result of an exception */
766 UnwindContext.Rip = *(DWORD64*)UnwindContext.Rsp;
767 UnwindContext.Rsp += sizeof(DWORD64);
768
769 if (HandlerType == UNW_FLAG_UHANDLER)
770 {
771 /* Copy the context back for the next iteration */
772 *ContextRecord = UnwindContext;
773 }
774 continue;
775 }
776
777 /* Save Rip before the virtual unwind */
778 DispatcherContext.ControlPc = UnwindContext.Rip;
779
780 /* Do a virtual unwind to get the next frame */
781 ExceptionRoutine = RtlVirtualUnwind(HandlerType,
782 ImageBase,
783 UnwindContext.Rip,
784 FunctionEntry,
785 &UnwindContext,
786 &DispatcherContext.HandlerData,
788 NULL);
789
790 /* Check, if we are still within the stack boundaries */
791 if ((EstablisherFrame < StackLow) ||
792 (EstablisherFrame >= StackHigh) ||
793 (EstablisherFrame & 7))
794 {
796
797 /* If we are handling an exception, we are done here. */
798 if (HandlerType == UNW_FLAG_EHANDLER)
799 {
800 ExceptionRecord->ExceptionFlags |= EXCEPTION_STACK_INVALID;
801 return FALSE;
802 }
803
804 __debugbreak();
806 }
807
808 /* Check if we have an exception routine */
809 if (ExceptionRoutine != NULL)
810 {
811 /* Check if this is the target frame */
812 if (EstablisherFrame == (ULONG64)TargetFrame)
813 {
814 /* Set flag to inform the language handler */
815 ExceptionRecord->ExceptionFlags |= EXCEPTION_TARGET_UNWIND;
816 }
817
818 /* Log the exception if it's enabled */
819 RtlpCheckLogException(ExceptionRecord,
820 &UnwindContext,
822 sizeof(DispatcherContext));
823
824 /* Set up the variable fields of the dispatcher context */
825 DispatcherContext.ImageBase = ImageBase;
826 DispatcherContext.FunctionEntry = FunctionEntry;
827 DispatcherContext.LanguageHandler = ExceptionRoutine;
828 DispatcherContext.EstablisherFrame = EstablisherFrame;
829 DispatcherContext.ScopeIndex = 0;
830
831 /* Store the return value in the unwind context */
832 UnwindContext.Rax = (ULONG64)ReturnValue;
833
834 /* Loop all nested handlers */
835 do
836 {
837 /* Call the language specific handler */
842
843 /* Clear exception flags for the next iteration */
844 ExceptionRecord->ExceptionFlags &= ~(EXCEPTION_TARGET_UNWIND |
846
847 /* Check if we do exception handling */
848 if (HandlerType == UNW_FLAG_EHANDLER)
849 {
851 {
852 /* Check if it was non-continuable */
853 if (ExceptionRecord->ExceptionFlags & EXCEPTION_NONCONTINUABLE)
854 {
855 __debugbreak();
857 }
858
859 /* Execution continues */
860 return TRUE;
861 }
863 {
865 __debugbreak();
866 }
867 }
868
870 {
871 /* We collided with another unwind, so we need to continue
872 "after" the handler, skipping the termination handler
873 that resulted in this unwind. The installed handler has
874 already copied the original dispatcher context, we now
875 need to copy back the original context. */
876 UnwindContext = *ContextRecord = *DispatcherContext.ContextRecord;
877
878 /* The original context was from "before" the unwind, so we
879 need to do an additional virtual unwind to restore the
880 unwind contxt. */
882 DispatcherContext.ImageBase,
883 UnwindContext.Rip,
884 DispatcherContext.FunctionEntry,
885 &UnwindContext,
886 &DispatcherContext.HandlerData,
888 NULL);
889
890 /* Restore the context pointer and establisher frame. */
891 DispatcherContext.ContextRecord = &UnwindContext;
892 EstablisherFrame = DispatcherContext.EstablisherFrame;
893
894 /* Set the exception flags to indicate that we collided
895 with an unwind and continue the handler loop, which
896 will run any additional handlers from the previous
897 unwind. */
898 ExceptionRecord->ExceptionFlags |= EXCEPTION_COLLIDED_UNWIND;
899 continue;
900 }
901
902 /* This must be ExceptionContinueSearch now */
904 {
905 __debugbreak();
907 }
908 } while (ExceptionRecord->ExceptionFlags & EXCEPTION_COLLIDED_UNWIND);
909 }
910
911 /* Check, if we have left our stack (8.) */
912 if ((EstablisherFrame < StackLow) ||
913 (EstablisherFrame > StackHigh) ||
914 (EstablisherFrame & 7))
915 {
917 __debugbreak();
918
919 if (UnwindContext.Rip == ContextRecord->Rip)
920 {
922 }
923 else
924 {
925 ZwRaiseException(ExceptionRecord, ContextRecord, FALSE);
926 }
927 }
928
929 if (EstablisherFrame == (ULONG64)TargetFrame)
930 {
931 break;
932 }
933
934 if (HandlerType == UNW_FLAG_UHANDLER)
935 {
936 /* We have successfully unwound a frame. Copy the unwind context back. */
937 *ContextRecord = UnwindContext;
938 }
939 }
940
941 if (ExceptionRecord->ExceptionCode != STATUS_UNWIND_CONSOLIDATE)
942 {
943 ContextRecord->Rip = (ULONG64)TargetIp;
944 }
945
946 /* Set the return value */
948
949 /* Restore the context */
950 RtlRestoreContext(ContextRecord, ExceptionRecord);
951
952 /* Should never get here! */
953 ASSERT(FALSE);
954 return FALSE;
955}
956
957VOID
958NTAPI
960 _In_opt_ PVOID TargetFrame,
961 _In_opt_ PVOID TargetIp,
962 _In_opt_ PEXCEPTION_RECORD ExceptionRecord,
965 _In_opt_ struct _UNWIND_HISTORY_TABLE *HistoryTable)
966{
967 EXCEPTION_RECORD LocalExceptionRecord;
968
969 /* Capture the current context */
971
972 /* Check if we have an exception record */
973 if (ExceptionRecord == NULL)
974 {
975 /* No exception record was passed, so set up a local one */
976 LocalExceptionRecord.ExceptionCode = STATUS_UNWIND;
977 LocalExceptionRecord.ExceptionAddress = (PVOID)ContextRecord->Rip;
978 LocalExceptionRecord.ExceptionRecord = NULL;
979 LocalExceptionRecord.NumberParameters = 0;
980 ExceptionRecord = &LocalExceptionRecord;
981 }
982
983 /* Set unwind flags */
984 ExceptionRecord->ExceptionFlags = EXCEPTION_UNWINDING;
985 if (TargetFrame == NULL)
986 {
987 ExceptionRecord->ExceptionFlags |= EXCEPTION_EXIT_UNWIND;
988 }
989
990 /* Call the internal function */
991 RtlpUnwindInternal(TargetFrame,
992 TargetIp,
993 ExceptionRecord,
996 HistoryTable,
997 UNW_FLAG_UHANDLER);
998}
999
1000VOID
1001NTAPI
1003 _In_opt_ PVOID TargetFrame,
1004 _In_opt_ PVOID TargetIp,
1005 _In_opt_ PEXCEPTION_RECORD ExceptionRecord,
1007{
1009
1010 RtlUnwindEx(TargetFrame,
1011 TargetIp,
1012 ExceptionRecord,
1014 &Context,
1015 NULL);
1016}
1017
1018ULONG
1019NTAPI
1021 IN ULONG Count,
1022 IN ULONG Flags)
1023{
1025 ULONG64 ControlPc, ImageBase, EstablisherFrame;
1026 ULONG64 StackLow, StackHigh;
1027 PVOID HandlerData;
1028 ULONG i, FramesToSkip;
1029 PRUNTIME_FUNCTION FunctionEntry;
1030 MODE CurrentMode = RtlpGetMode();
1031
1032 DPRINT("Enter RtlWalkFrameChain\n");
1033
1034 /* The upper bits in Flags define how many frames to skip */
1035 FramesToSkip = Flags >> 8;
1036
1037 /* Capture the current Context */
1039 ControlPc = Context.Rip;
1040
1041 /* Get the stack limits */
1042 RtlpGetStackLimits(&StackLow, &StackHigh);
1043
1044 _SEH2_TRY
1045 {
1046 /* Loop the frames */
1047 for (i = 0; i < FramesToSkip + Count; i++)
1048 {
1049 /* Lookup the FunctionEntry for the current ControlPc */
1050 FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);
1051
1052 /* Is this a leaf function? */
1053 if (!FunctionEntry)
1054 {
1055 Context.Rip = *(DWORD64*)Context.Rsp;
1056 Context.Rsp += sizeof(DWORD64);
1057 DPRINT("leaf funtion, new Rip = %p, new Rsp = %p\n", (PVOID)Context.Rip, (PVOID)Context.Rsp);
1058 }
1059 else
1060 {
1062 ImageBase,
1063 ControlPc,
1064 FunctionEntry,
1065 &Context,
1066 &HandlerData,
1068 NULL);
1069 DPRINT("normal funtion, new Rip = %p, new Rsp = %p\n", (PVOID)Context.Rip, (PVOID)Context.Rsp);
1070 }
1071
1072 /* Check if we are in kernel mode */
1073 if (CurrentMode == KernelMode)
1074 {
1075 /* Check if we left the kernel range */
1076 if (Context.Rip < 0xFFFF800000000000ULL)
1077 {
1078 /* Bail out, unless user mode was requested */
1079 if ((Flags & 1) == 0)
1080 {
1081 break;
1082 }
1083
1084 /* We are in user mode now, get UM stack bounds */
1085 CurrentMode = UserMode;
1086 StackLow = (ULONG64)NtCurrentTeb()->NtTib.StackLimit;
1087 StackHigh = (ULONG64)NtCurrentTeb()->NtTib.StackBase;
1088 }
1089 }
1090
1091 /* Check (again) if we are in user mode now */
1092 if (CurrentMode == UserMode)
1093 {
1094 /* Check if we left the user range */
1095 if ((Context.Rip < 0x10000) ||
1096 (Context.Rip > 0x000007FFFFFEFFFFULL))
1097 {
1098 break;
1099 }
1100 }
1101
1102 /* Check, if we have left our stack */
1103 if ((Context.Rsp <= StackLow) || (Context.Rsp >= StackHigh))
1104 {
1105 break;
1106 }
1107
1108 /* Continue with new Rip */
1109 ControlPc = Context.Rip;
1110
1111 /* Save value, if we are past the frames to skip */
1112 if (i >= FramesToSkip)
1113 {
1114 Callers[i - FramesToSkip] = (PVOID)ControlPc;
1115 }
1116 }
1117 }
1119 {
1120 DPRINT1("Exception while getting callers!\n");
1121 i = 0;
1122 }
1123 _SEH2_END;
1124
1125 DPRINT("RtlWalkFrameChain returns %ld\n", i);
1126 return i;
1127}
1128
1132#undef RtlGetCallersAddress
1133VOID
1134NTAPI
1136 OUT PVOID *CallersAddress,
1137 OUT PVOID *CallersCaller )
1138{
1139 PVOID Callers[4];
1140 ULONG Number;
1141
1142 /* Get callers:
1143 * RtlWalkFrameChain -> RtlGetCallersAddress -> x -> y */
1144 Number = RtlWalkFrameChain(Callers, 4, 0);
1145
1146 *CallersAddress = (Number >= 3) ? Callers[2] : NULL;
1147 *CallersCaller = (Number == 4) ? Callers[3] : NULL;
1148
1149 return;
1150}
1151
1152static
1153VOID
1155 _Out_ PKNONVOLATILE_CONTEXT_POINTERS NonvolatileContextPointers,
1156 _In_ ULONG64 TargetFrame)
1157{
1159 PRUNTIME_FUNCTION FunctionEntry;
1160 ULONG64 ImageBase;
1161 PVOID HandlerData;
1163
1164 /* Zero out the nonvolatile context pointers */
1165 RtlZeroMemory(NonvolatileContextPointers, sizeof(*NonvolatileContextPointers));
1166
1167 /* Capture the current context */
1169
1170 do
1171 {
1172 /* Make sure nothing fishy is going on. Currently this is for kernel mode only. */
1173 ASSERT((LONG64)Context.Rip < 0);
1174 ASSERT((LONG64)Context.Rsp < 0);
1175
1176 /* Look up the function entry */
1177 FunctionEntry = RtlLookupFunctionEntry(Context.Rip, &ImageBase, NULL);
1178 if (FunctionEntry != NULL)
1179 {
1180 /* Do a virtual unwind to the caller and capture saved non-volatiles */
1181 RtlVirtualUnwind(UNW_FLAG_EHANDLER,
1182 ImageBase,
1183 Context.Rip,
1184 FunctionEntry,
1185 &Context,
1186 &HandlerData,
1188 NonvolatileContextPointers);
1189
1191 }
1192 else
1193 {
1194 Context.Rip = *(PULONG64)Context.Rsp;
1195 Context.Rsp += 8;
1196 }
1197
1198 /* Continue until we reach user mode */
1199 } while ((LONG64)Context.Rip < 0);
1200
1201 /* If the caller did the right thing, we should get past the target frame */
1202 ASSERT(EstablisherFrame >= TargetFrame);
1203}
1204
1205VOID
1208 _In_ DWORD64 TargetFrame)
1209{
1210 KNONVOLATILE_CONTEXT_POINTERS ContextPointers;
1211 ULONG ContextFlags = Context->ContextFlags & ~CONTEXT_AMD64;
1212
1213 /* Capture pointers to the non-volatiles up to the target frame */
1214 RtlpCaptureNonVolatileContextPointers(&ContextPointers, TargetFrame);
1215
1216 /* Copy the nonvolatiles from the captured locations */
1217 if (ContextFlags & CONTEXT_INTEGER)
1218 {
1219 Context->Rbx = *ContextPointers.Rbx;
1220 Context->Rsi = *ContextPointers.Rsi;
1221 Context->Rdi = *ContextPointers.Rdi;
1222 Context->R12 = *ContextPointers.R12;
1223 Context->R13 = *ContextPointers.R13;
1224 Context->R14 = *ContextPointers.R14;
1225 Context->R15 = *ContextPointers.R15;
1226 }
1227 if (ContextFlags & CONTEXT_FLOATING_POINT)
1228 {
1229 Context->Xmm6 = *ContextPointers.Xmm6;
1230 Context->Xmm7 = *ContextPointers.Xmm7;
1231 Context->Xmm8 = *ContextPointers.Xmm8;
1232 Context->Xmm9 = *ContextPointers.Xmm9;
1233 Context->Xmm10 = *ContextPointers.Xmm10;
1234 Context->Xmm11 = *ContextPointers.Xmm11;
1235 Context->Xmm12 = *ContextPointers.Xmm12;
1236 Context->Xmm13 = *ContextPointers.Xmm13;
1237 Context->Xmm14 = *ContextPointers.Xmm14;
1238 Context->Xmm15 = *ContextPointers.Xmm15;
1239 }
1240}
1241
1242VOID
1245 _In_ DWORD64 TargetFrame)
1246{
1247 KNONVOLATILE_CONTEXT_POINTERS ContextPointers;
1248 ULONG ContextFlags = Context->ContextFlags & ~CONTEXT_AMD64;
1249
1250 /* Capture pointers to the non-volatiles up to the target frame */
1251 RtlpCaptureNonVolatileContextPointers(&ContextPointers, TargetFrame);
1252
1253 /* Copy the nonvolatiles to the captured locations */
1254 if (ContextFlags & CONTEXT_INTEGER)
1255 {
1256 *ContextPointers.Rbx = Context->Rbx;
1257 *ContextPointers.Rsi = Context->Rsi;
1258 *ContextPointers.Rdi = Context->Rdi;
1259 *ContextPointers.R12 = Context->R12;
1260 *ContextPointers.R13 = Context->R13;
1261 *ContextPointers.R14 = Context->R14;
1262 *ContextPointers.R15 = Context->R15;
1263 }
1264 if (ContextFlags & CONTEXT_FLOATING_POINT)
1265 {
1266 *ContextPointers.Xmm6 = Context->Xmm6;
1267 *ContextPointers.Xmm7 = Context->Xmm7;
1268 *ContextPointers.Xmm8 = Context->Xmm8;
1269 *ContextPointers.Xmm9 = Context->Xmm9;
1270 *ContextPointers.Xmm10 = Context->Xmm10;
1271 *ContextPointers.Xmm11 = Context->Xmm11;
1272 *ContextPointers.Xmm12 = Context->Xmm12;
1273 *ContextPointers.Xmm13 = Context->Xmm13;
1274 *ContextPointers.Xmm14 = Context->Xmm14;
1275 *ContextPointers.Xmm15 = Context->Xmm15;
1276 }
1277}
1278
1279VOID
1282
1283VOID
1286 _In_ PEXCEPTION_RECORD ExceptionRecord)
1287{
1288 if (ExceptionRecord != NULL)
1289 {
1290 if ((ExceptionRecord->ExceptionCode == STATUS_UNWIND_CONSOLIDATE) &&
1291 (ExceptionRecord->NumberParameters >= 1))
1292 {
1293 PVOID (*Consolidate)(EXCEPTION_RECORD*) = (PVOID)ExceptionRecord->ExceptionInformation[0];
1294 // FIXME: This should be called through an asm wrapper to allow handling recursive unwinding
1295 ContextRecord->Rip = (ULONG64)Consolidate(ExceptionRecord);
1296 }
1297 else if ((ExceptionRecord->ExceptionCode == STATUS_LONGJUMP) &&
1298 (ExceptionRecord->NumberParameters >= 1))
1299 {
1300 _JUMP_BUFFER* JumpBuffer = (_JUMP_BUFFER*)ExceptionRecord->ExceptionInformation[0];
1301 ContextRecord->Rbx = JumpBuffer->Rbx;
1302 ContextRecord->Rsp = JumpBuffer->Rsp;
1303 ContextRecord->Rbp = JumpBuffer->Rbp;
1304 ContextRecord->Rsi = JumpBuffer->Rsi;
1305 ContextRecord->Rdi = JumpBuffer->Rdi;
1306 ContextRecord->R12 = JumpBuffer->R12;
1307 ContextRecord->R13 = JumpBuffer->R13;
1308 ContextRecord->R14 = JumpBuffer->R14;
1309 ContextRecord->R15 = JumpBuffer->R15;
1310 ContextRecord->Rip = JumpBuffer->Rip;
1311 ContextRecord->MxCsr = JumpBuffer->MxCsr;
1312 ContextRecord->FltSave.MxCsr = JumpBuffer->MxCsr;
1313 ContextRecord->FltSave.ControlWord = JumpBuffer->FpCsr;
1314 ContextRecord->Xmm6 = *(M128A*)&JumpBuffer->Xmm6;
1315 ContextRecord->Xmm7 = *(M128A*)&JumpBuffer->Xmm7;
1316 ContextRecord->Xmm8 = *(M128A*)&JumpBuffer->Xmm8;
1317 ContextRecord->Xmm9 = *(M128A*)&JumpBuffer->Xmm9;
1318 ContextRecord->Xmm10 = *(M128A*)&JumpBuffer->Xmm10;
1319 ContextRecord->Xmm11 = *(M128A*)&JumpBuffer->Xmm11;
1320 ContextRecord->Xmm12 = *(M128A*)&JumpBuffer->Xmm12;
1321 ContextRecord->Xmm13 = *(M128A*)&JumpBuffer->Xmm13;
1322 ContextRecord->Xmm14 = *(M128A*)&JumpBuffer->Xmm14;
1323 ContextRecord->Xmm15 = *(M128A*)&JumpBuffer->Xmm15;
1324 }
1325 }
1326
1328}
unsigned char BOOLEAN
#define __inline
Definition: _wctype.cpp:15
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
#define RtlUnwind
Definition: longjmp.c:9
#define DPRINT1
Definition: precomp.h:8
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
VOID NTAPI RtlpCheckLogException(IN PEXCEPTION_RECORD ExceptionRecord, IN PCONTEXT ContextRecord, IN PVOID ContextData, IN ULONG Size)
Definition: libsupp.c:203
KPROCESSOR_MODE NTAPI RtlpGetMode(VOID)
Definition: libsupp.c:55
PVOID NTAPI RtlPcToFileHeader(IN PVOID PcValue, PVOID *BaseOfImage)
Definition: libsupp.c:658
VOID NTAPI RtlpGetStackLimits(OUT PULONG_PTR LowLimit, OUT PULONG_PTR HighLimit)
Definition: libsupp.c:337
@ 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
#define RtlImageDirectoryEntryToData
Definition: compat.h:809
enum _EXCEPTION_DISPOSITION EXCEPTION_DISPOSITION
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
#define RVA(m, b)
Definition: freeldr.h:28
ASMGENDATA Table[]
Definition: genincdata.c:61
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 UNW_FLAG_NHANDLER
Definition: gs_support.c:32
#define EXCEPTION_EXECUTE_HANDLER
Definition: excpt.h:90
void __cdecl __debugbreak(void)
Definition: intrin_ppc.h:698
#define NtCurrentTeb
#define EXCEPTION_NONCONTINUABLE_EXCEPTION
Definition: minwinbase.h:61
#define ASSERT(a)
Definition: mode.c:44
unsigned __int64 * PULONG64
Definition: imports.h:198
unsigned __int64 ULONG64
Definition: imports.h:198
struct _DISPATCHER_CONTEXT * PDISPATCHER_CONTEXT
_In_ ACCESS_MASK _In_ POBJECT_ATTRIBUTES _Reserved_ ULONG _In_opt_ PUNICODE_STRING _In_ ULONG _Out_opt_ PULONG Disposition
Definition: cmfuncs.h:56
#define KernelMode
Definition: asm.h:38
#define UserMode
Definition: asm.h:39
NTSYSAPI NTSTATUS NTAPI ZwRaiseException(_In_ PEXCEPTION_RECORD ExceptionRecord, _In_ PCONTEXT Context, _In_ BOOLEAN SearchFrames)
DECLSPEC_NORETURN NTSYSAPI VOID NTAPI RtlRaiseStatus(_In_ NTSTATUS Status)
NTSYSAPI VOID NTAPI RtlCaptureContext(_Out_ PCONTEXT ContextRecord)
#define _Inout_
Definition: no_sal2.h:162
#define _Outptr_
Definition: no_sal2.h:262
#define _Inout_opt_
Definition: no_sal2.h:216
#define _Out_
Definition: no_sal2.h:160
#define _In_
Definition: no_sal2.h:158
#define _In_opt_
Definition: no_sal2.h:212
int Count
Definition: noreturn.cpp:7
#define CONTEXT_INTEGER
Definition: nt_native.h:1373
#define CONTEXT_FLOATING_POINT
Definition: nt_native.h:1375
_IRQL_requires_same_ _In_ PVOID EstablisherFrame
Definition: ntbasedef.h:665
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT * ContextRecord
Definition: ntbasedef.h:666
_IRQL_requires_same_ _In_ PVOID _Inout_ struct _CONTEXT _In_ PVOID DispatcherContext
Definition: ntbasedef.h:667
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
_In_opt_ PENTER_STATE_SYSTEM_HANDLER _In_opt_ PVOID _In_ LONG _In_opt_ LONG volatile * Number
Definition: ntpoapi.h:207
#define STATUS_INVALID_DISPOSITION
Definition: ntstatus.h:368
#define STATUS_LONGJUMP
Definition: ntstatus.h:297
#define STATUS_UNWIND
Definition: ntstatus.h:369
#define STATUS_UNWIND_CONSOLIDATE
Definition: ntstatus.h:300
#define STATUS_BAD_FUNCTION_TABLE
Definition: ntstatus.h:585
#define STATUS_BAD_STACK
Definition: ntstatus.h:370
#define IMAGE_DIRECTORY_ENTRY_EXCEPTION
Definition: pedump.c:262
long LONG
Definition: pedump.c:60
unsigned short USHORT
Definition: pedump.c:61
#define _SEH2_EXCEPT(...)
Definition: pseh2_64.h:82
#define _SEH2_END
Definition: pseh2_64.h:171
#define _SEH2_TRY
Definition: pseh2_64.h:71
EXCEPTION_DISPOSITION NTAPI RtlpExecuteHandlerForUnwind(_Inout_ struct _EXCEPTION_RECORD *ExceptionRecord, _In_ PVOID EstablisherFrame, _Inout_ struct _CONTEXT *ContextRecord, _In_ PVOID DispatcherContext)
#define DPRINT
Definition: sndvol32.h:73
static void Exit(void)
Definition: sock.c:1330
struct _EXCEPTION_RECORD * ExceptionRecord
Definition: compat.h:210
DWORD ExceptionCode
Definition: compat.h:208
DWORD NumberParameters
Definition: compat.h:212
DWORD ExceptionFlags
Definition: compat.h:209
PVOID ExceptionAddress
Definition: compat.h:211
BYTE CountOfCodes
Definition: cpu_x86_64.c:65
UBYTE CountOfCodes
Definition: unwind.c:55
UBYTE FrameRegister
Definition: unwind.c:56
BYTE FrameOffset
Definition: cpu_x86_64.c:67
UBYTE Version
Definition: unwind.c:52
UBYTE SizeOfProlog
Definition: unwind.c:54
UNWIND_CODE UnwindCode[1]
Definition: cpu_x86_64.c:68
BYTE SizeOfProlog
Definition: cpu_x86_64.c:64
UBYTE FrameOffset
Definition: unwind.c:57
UBYTE Flags
Definition: unwind.c:53
BYTE FrameRegister
Definition: cpu_x86_64.c:66
#define EXCEPTION_NONCONTINUABLE
Definition: stubs.h:23
uint64_t * PDWORD64
Definition: typedefs.h:67
uint32_t * PULONG
Definition: typedefs.h:59
int64_t LONG64
Definition: typedefs.h:68
uint64_t DWORD64
Definition: typedefs.h:67
#define NTAPI
Definition: typedefs.h:36
void * PVOID
Definition: typedefs.h:50
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#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
UBYTE UnwindOp
Definition: unwind.c:44
UBYTE OpInfo
Definition: unwind.c:45
UBYTE CodeOffset
Definition: unwind.c:43
PEXCEPTION_ROUTINE NTAPI RtlVirtualUnwind(_In_ ULONG HandlerType, _In_ ULONG64 ImageBase, _In_ ULONG64 ControlPc, _In_ PRUNTIME_FUNCTION FunctionEntry, _Inout_ PCONTEXT Context, _Outptr_ PVOID *HandlerData, _Out_ PULONG64 EstablisherFrame, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers)
Definition: unwind.c:478
static __inline M128A GetXmmReg(PCONTEXT Context, BYTE Reg)
Definition: unwind.c:286
VOID NTAPI RtlGetCallersAddress(OUT PVOID *CallersAddress, OUT PVOID *CallersCaller)
Definition: unwind.c:1135
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:717
#define UWOP_EPILOG
Definition: unwind.c:29
unsigned char UBYTE
Definition: unwind.c:37
static __inline void PopReg(_Inout_ PCONTEXT Context, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ BYTE Reg)
Definition: unwind.c:247
VOID RtlRestoreContext(_In_ PCONTEXT ContextRecord, _In_ PEXCEPTION_RECORD ExceptionRecord)
Definition: unwind.c:1284
#define UWOP_SAVE_NONVOL
Definition: unwind.c:23
static VOID RtlpCaptureNonVolatileContextPointers(_Out_ PKNONVOLATILE_CONTEXT_POINTERS NonvolatileContextPointers, _In_ ULONG64 TargetFrame)
Definition: unwind.c:1154
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:959
union _UNWIND_CODE UNWIND_CODE
#define UWOP_SPARE_CODE
Definition: unwind.c:30
static ULONG64 GetEstablisherFrame(_In_ PCONTEXT Context, _In_ PUNWIND_INFO UnwindInfo, _In_ ULONG_PTR CodeOffset)
Definition: unwind.c:433
struct _UNWIND_INFO * PUNWIND_INFO
#define UWOP_SAVE_NONVOL_FAR
Definition: unwind.c:24
ULONG NTAPI RtlWalkFrameChain(OUT PVOID *Callers, IN ULONG Count, IN ULONG Flags)
Definition: unwind.c:1020
PRUNTIME_FUNCTION NTAPI RtlpLookupDynamicFunctionEntry(_In_ DWORD64 ControlPc, _Out_ PDWORD64 ImageBase, _In_ PUNWIND_HISTORY_TABLE HistoryTable)
Definition: dynfntbl.c:275
static __inline void SetXmmReg(_Inout_ PCONTEXT Context, _In_ BYTE Reg, _In_ M128A Value)
Definition: unwind.c:259
static __inline void SetReg(_Inout_ PCONTEXT Context, _In_ BYTE Reg, _In_ DWORD64 Value)
Definition: unwind.c:210
static __inline void SetRegFromStackValue(_Inout_ PCONTEXT Context, _Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, _In_ BYTE Reg, _In_ PDWORD64 ValuePointer)
Definition: unwind.c:221
EXCEPTION_DISPOSITION RtlpExecuteHandlerForUnwindHandler(_Inout_ PEXCEPTION_RECORD ExceptionRecord, _In_ PVOID EstablisherFrame, _Inout_ PCONTEXT ContextRecord, _In_ PDISPATCHER_CONTEXT DispatcherContext)
Definition: unwind.c:665
PRUNTIME_FUNCTION NTAPI RtlLookupFunctionEntry(IN DWORD64 ControlPc, OUT PDWORD64 ImageBase, OUT PUNWIND_HISTORY_TABLE HistoryTable)
Locates the RUNTIME_FUNCTION entry corresponding to a code address. https://learn....
Definition: unwind.c:124
static __inline ULONG UnwindOpSlots(_In_ UNWIND_CODE UnwindCode)
Definition: unwind.c:177
#define UWOP_PUSH_MACHFRAME
Definition: unwind.c:34
#define UWOP_ALLOC_LARGE
Definition: unwind.c:20
struct _UNWIND_INFO UNWIND_INFO
static __inline DWORD64 GetReg(_In_ PCONTEXT Context, _In_ BYTE Reg)
Definition: unwind.c:237
union _UNWIND_CODE * PUNWIND_CODE
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
VOID RtlpRestoreContextInternal(_In_ PCONTEXT ContextRecord)
static __inline BOOL RtlpIsStackPointerValid(_In_ ULONG64 StackPointer, _In_ ULONG64 LowLimit, _In_ ULONG64 HighLimit)
Definition: unwind.c:654
#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
VOID RtlGetUnwindContext(_Out_ PCONTEXT Context, _In_ DWORD64 TargetFrame)
Definition: unwind.c:1206
VOID RtlSetUnwindContext(_In_ PCONTEXT Context, _In_ DWORD64 TargetFrame)
Definition: unwind.c:1243
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 UWOP_PUSH_NONVOL
Definition: unwind.c:19
#define UWOP_SET_FPREG
Definition: unwind.c:22
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4539
_Must_inspect_result_ _In_ WDFKEY _In_ PCUNICODE_STRING _Out_opt_ PUSHORT _Inout_opt_ PUNICODE_STRING Value
Definition: wdfregistry.h:413
static WLX_DISPATCH_VERSION_1_4 FunctionTable
Definition: wlx.c:747
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
_Out_ PULONG_PTR HighLimit
Definition: iofuncs.h:2885
M128A
Definition: ketypes.h:992
enum _MODE MODE
#define EXCEPTION_EXIT_UNWIND
Definition: rtltypes.h:156
#define IS_UNWINDING(Flag)
Definition: rtltypes.h:164
#define EXCEPTION_STACK_INVALID
Definition: rtltypes.h:157
#define EXCEPTION_UNWINDING
Definition: rtltypes.h:155
#define EXCEPTION_TARGET_UNWIND
Definition: rtltypes.h:159
#define EXCEPTION_COLLIDED_UNWIND
Definition: rtltypes.h:160
unsigned char UCHAR
Definition: xmlstorage.h:181
char CHAR
Definition: xmlstorage.h:175
unsigned char BYTE
Definition: xxhash.c:193