https://git.reactos.org/?p=reactos.git;a=commitdiff;h=aade1ab01beedac84af67…
commit aade1ab01beedac84af6712e8cf02128b34021b3
Author: Timo Kreuzer <timo.kreuzer(a)reactos.org>
AuthorDate: Fri Aug 19 13:03:22 2022 +0200
Commit: Timo Kreuzer <timo.kreuzer(a)reactos.org>
CommitDate: Thu Nov 24 21:17:58 2022 +0200
[RTL] Fix RtlVirtualUnwind
---
sdk/lib/rtl/amd64/unwind.c | 53 ++++++++++++++++++++++++++--------------------
1 file changed, 30 insertions(+), 23 deletions(-)
diff --git a/sdk/lib/rtl/amd64/unwind.c b/sdk/lib/rtl/amd64/unwind.c
index 33a7e71c857..2b596341eb0 100644
--- a/sdk/lib/rtl/amd64/unwind.c
+++ b/sdk/lib/rtl/amd64/unwind.c
@@ -303,6 +303,7 @@ __inline
BOOLEAN
RtlpTryToUnwindEpilog(
_Inout_ PCONTEXT Context,
+ _In_ ULONG64 ControlPc,
_Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers,
_In_ ULONG64 ImageBase,
_In_ PRUNTIME_FUNCTION FunctionEntry)
@@ -316,7 +317,7 @@ RtlpTryToUnwindEpilog(
/* Make a local copy of the context */
LocalContext = *Context;
- InstrPtr = (BYTE*)LocalContext.Rip;
+ InstrPtr = (BYTE*)ControlPc;
/* Check if first instruction of epilog is "add rsp, x" */
Instr = *(DWORD*)InstrPtr;
@@ -339,7 +340,10 @@ RtlpTryToUnwindEpilog(
else if ( (Instr & 0x38fffe) == 0x208d48 )
{
/* Get the register */
- Reg = ((Instr << 8) | (Instr >> 16)) & 0x7;
+ Reg = (Instr >> 16) & 0x7;
+
+ /* REX.R */
+ Reg += (Instr & 1) * 8;
LocalContext.Rsp = GetReg(&LocalContext, Reg);
@@ -353,13 +357,13 @@ RtlpTryToUnwindEpilog(
else if (Mod == 1)
{
/* 1 byte displacement */
- LocalContext.Rsp += Instr >> 24;
+ LocalContext.Rsp += (LONG)(CHAR)(Instr >> 24);
InstrPtr += 4;
}
else if (Mod == 2)
{
/* 4 bytes displacement */
- LocalContext.Rsp += *(DWORD*)(InstrPtr + 3);
+ LocalContext.Rsp += *(LONG*)(InstrPtr + 3);
InstrPtr += 7;
}
}
@@ -453,11 +457,17 @@ GetEstablisherFrame(
i < UnwindInfo->CountOfCodes;
i += UnwindOpSlots(UnwindInfo->UnwindCode[i]))
{
+ /* Skip codes past our code offset */
+ if (UnwindInfo->UnwindCode[i].CodeOffset > CodeOffset)
+ {
+ continue;
+ }
+
/* Check for SET_FPREG */
if (UnwindInfo->UnwindCode[i].UnwindOp == UWOP_SET_FPREG)
{
return GetReg(Context, UnwindInfo->FrameRegister) -
- UnwindInfo->FrameOffset * 16;
+ UnwindInfo->FrameOffset * 16;
}
}
@@ -477,18 +487,18 @@ RtlVirtualUnwind(
_Inout_opt_ PKNONVOLATILE_CONTEXT_POINTERS ContextPointers)
{
PUNWIND_INFO UnwindInfo;
- ULONG_PTR CodeOffset;
+ ULONG_PTR ControlRva, CodeOffset;
ULONG i, Offset;
UNWIND_CODE UnwindCode;
BYTE Reg;
PULONG LanguageHandler;
- /* Use relative virtual address */
- ControlPc -= ImageBase;
+ /* Get relative virtual address */
+ ControlRva = ControlPc - ImageBase;
/* Sanity checks */
- if ( (ControlPc < FunctionEntry->BeginAddress) ||
- (ControlPc >= FunctionEntry->EndAddress) )
+ if ( (ControlRva < FunctionEntry->BeginAddress) ||
+ (ControlRva >= FunctionEntry->EndAddress) )
{
return NULL;
}
@@ -498,17 +508,16 @@ RtlVirtualUnwind(
/* The language specific handler data follows the unwind info */
LanguageHandler =
ALIGN_UP_POINTER_BY(&UnwindInfo->UnwindCode[UnwindInfo->CountOfCodes],
sizeof(ULONG));
- *HandlerData = (LanguageHandler + 1);
/* Calculate relative offset to function start */
- CodeOffset = ControlPc - FunctionEntry->BeginAddress;
+ CodeOffset = ControlRva - FunctionEntry->BeginAddress;
*EstablisherFrame = GetEstablisherFrame(Context, UnwindInfo, CodeOffset);
/* Check if we are in the function epilog and try to finish it */
- if (CodeOffset > UnwindInfo->SizeOfProlog)
+ if ((CodeOffset > UnwindInfo->SizeOfProlog) &&
(UnwindInfo->CountOfCodes > 0))
{
- if (RtlpTryToUnwindEpilog(Context, ContextPointers, ImageBase, FunctionEntry))
+ if (RtlpTryToUnwindEpilog(Context, ControlPc, ContextPointers, ImageBase,
FunctionEntry))
{
/* There's no exception routine */
return NULL;
@@ -565,7 +574,7 @@ RepeatChainedInfo:
case UWOP_SAVE_NONVOL:
Reg = UnwindCode.OpInfo;
- Offset = *(USHORT*)(&UnwindInfo->UnwindCode[i + 1]);
+ Offset = UnwindInfo->UnwindCode[i + 1].FrameOffset;
SetRegFromStackValue(Context, ContextPointers, Reg,
(DWORD64*)Context->Rsp + Offset);
i += 2;
break;
@@ -588,15 +597,15 @@ RepeatChainedInfo:
case UWOP_SAVE_XMM128:
Reg = UnwindCode.OpInfo;
- Offset = *(USHORT*)(&UnwindInfo->UnwindCode[i + 1]);
- SetXmmRegFromStackValue(Context, ContextPointers, Reg,
(M128A*)(Context->Rsp + Offset));
+ Offset = UnwindInfo->UnwindCode[i + 1].FrameOffset;
+ SetXmmRegFromStackValue(Context, ContextPointers, Reg,
(M128A*)Context->Rsp + Offset);
i += 2;
break;
case UWOP_SAVE_XMM128_FAR:
Reg = UnwindCode.OpInfo;
Offset = *(ULONG*)(&UnwindInfo->UnwindCode[i + 1]);
- SetXmmRegFromStackValue(Context, ContextPointers, Reg,
(M128A*)(Context->Rsp + Offset));
+ SetXmmRegFromStackValue(Context, ContextPointers, Reg,
(M128A*)Context->Rsp + Offset);
i += 3;
break;
@@ -604,11 +613,8 @@ RepeatChainedInfo:
/* OpInfo is 1, when an error code was pushed, otherwise 0. */
Context->Rsp += UnwindCode.OpInfo * sizeof(DWORD64);
- /* Now pop the MACHINE_FRAME (Yes, "magic numbers", deal with
it) */
+ /* Now pop the MACHINE_FRAME (RIP/RSP only. And yes, "magic
numbers", deal with it) */
Context->Rip = *(PDWORD64)(Context->Rsp + 0x00);
- Context->SegCs = *(PDWORD64)(Context->Rsp + 0x08);
- Context->EFlags = *(PDWORD64)(Context->Rsp + 0x10);
- Context->SegSs = *(PDWORD64)(Context->Rsp + 0x20);
Context->Rsp = *(PDWORD64)(Context->Rsp + 0x18);
ASSERT((i + 1) == UnwindInfo->CountOfCodes);
goto Exit;
@@ -635,8 +641,9 @@ RepeatChainedInfo:
Exit:
/* Check if we have a handler and return it */
- if (UnwindInfo->Flags & (UNW_FLAG_EHANDLER | UNW_FLAG_UHANDLER))
+ if (UnwindInfo->Flags & (HandlerType & (UNW_FLAG_EHANDLER |
UNW_FLAG_UHANDLER)))
{
+ *HandlerData = (LanguageHandler + 1);
return RVA(ImageBase, *LanguageHandler);
}