https://git.reactos.org/?p=reactos.git;a=commitdiff;h=aade1ab01beedac84af671...
commit aade1ab01beedac84af6712e8cf02128b34021b3 Author: Timo Kreuzer timo.kreuzer@reactos.org AuthorDate: Fri Aug 19 13:03:22 2022 +0200 Commit: Timo Kreuzer timo.kreuzer@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); }