From 29d32d571bfb8ed844de4a2549baa8ae65aa3155 Mon Sep 17 00:00:00 2001 From: Jonghyun Park Date: Thu, 18 May 2017 12:34:05 +0900 Subject: [PATCH 26/29] Port 'DacUnwindStackFrame' (#11666) * [x86/Linux] Implement 'DacUnwindStackFrame' * Update ContextPointers using ContextRecord * An attempt to fix x86/Windows build error --- src/inc/regdisp.h | 56 +++++++++++++---------- src/unwinder/i386/unwinder_i386.cpp | 88 ++++++++++++++++++++++++------------- src/unwinder/i386/unwinder_i386.h | 2 + 3 files changed, 91 insertions(+), 55 deletions(-) diff --git a/src/inc/regdisp.h b/src/inc/regdisp.h index a361dca..eb84fdf 100644 --- a/src/inc/regdisp.h +++ b/src/inc/regdisp.h @@ -323,6 +323,35 @@ inline void SyncRegDisplayToCurrentContext(REGDISPLAY* pRD) typedef REGDISPLAY *PREGDISPLAY; +#ifdef WIN64EXCEPTIONS +inline void FillContextPointers(PT_KNONVOLATILE_CONTEXT_POINTERS pCtxPtrs, PT_CONTEXT pCtx) +{ +#ifdef _TARGET_AMD64_ + for (int i = 0; i < 16; i++) + { + *(&pCtxPtrs->Rax + i) = (&pCtx->Rax + i); + } +#elif defined(_TARGET_ARM64_) // _TARGET_AMD64_ + for (int i = 0; i < 12; i++) + { + *(&pCtxPtrs->X19 + i) = (&pCtx->X19 + i); + } +#elif defined(_TARGET_ARM_) // _TARGET_ARM64_ + // Copy over the nonvolatile integer registers (R4-R11) + for (int i = 0; i < 8; i++) + { + *(&pCtxPtrs->R4 + i) = (&pCtx->R4 + i); + } +#elif defined(_TARGET_X86_) // _TARGET_ARM_ + for (int i = 0; i < 7; i++) + { + *(&pCtxPtrs->Edi + i) = (&pCtx->Edi + i); + } +#else // _TARGET_X86_ + PORTABILITY_ASSERT("FillContextPointers"); +#endif // _TARGET_???_ (ELSE) +} +#endif // WIN64EXCEPTIONS inline void FillRegDisplay(const PREGDISPLAY pRD, PT_CONTEXT pctx, PT_CONTEXT pCallerCtx = NULL) { @@ -374,33 +403,12 @@ inline void FillRegDisplay(const PREGDISPLAY pRD, PT_CONTEXT pctx, PT_CONTEXT pC pRD->IsCallerSPValid = TRUE; // Don't add usage of this field. This is only temporary. } -#ifdef _TARGET_AMD64_ - for (int i = 0; i < 16; i++) - { - *(&pRD->ctxPtrsOne.Rax + i) = (&pctx->Rax + i); - } -#elif defined(_TARGET_ARM64_) // _TARGET_AMD64_ - for (int i = 0; i < 12; i++) - { - *(&pRD->ctxPtrsOne.X19 + i) = (&pctx->X19 + i); - } -#elif defined(_TARGET_ARM_) // _TARGET_ARM64_ - // Copy over the nonvolatile integer registers (R4-R11) - for (int i = 0; i < 8; i++) - { - *(&pRD->ctxPtrsOne.R4 + i) = (&pctx->R4 + i); - } + FillContextPointers(&pRD->ctxPtrsOne, pctx); +#if defined(_TARGET_ARM_) pRD->ctxPtrsOne.Lr = &pctx->Lr; pRD->pPC = &pRD->pCurrentContext->Pc; -#elif defined(_TARGET_X86_) // _TARGET_ARM_ - for (int i = 0; i < 7; i++) - { - *(&pRD->ctxPtrsOne.Edi + i) = (&pctx->Edi + i); - } -#else // _TARGET_X86_ - PORTABILITY_ASSERT("FillRegDisplay"); -#endif // _TARGET_???_ (ELSE) +#endif // _TARGET_ARM_ #ifdef DEBUG_REGDISPLAY pRD->_pThread = NULL; diff --git a/src/unwinder/i386/unwinder_i386.cpp b/src/unwinder/i386/unwinder_i386.cpp index f221020..42c19cb 100644 --- a/src/unwinder/i386/unwinder_i386.cpp +++ b/src/unwinder/i386/unwinder_i386.cpp @@ -8,6 +8,49 @@ #include "unwinder_i386.h" #ifdef WIN64EXCEPTIONS +BOOL OOPStackUnwinderX86::Unwind(T_CONTEXT* pContextRecord, T_KNONVOLATILE_CONTEXT_POINTERS* pContextPointers) +{ + REGDISPLAY rd; + + FillRegDisplay(&rd, pContextRecord); + + rd.SP = pContextRecord->Esp; + rd.PCTAddr = (UINT_PTR)&(pContextRecord->Eip); + + if (pContextPointers) + { + rd.pCurrentContextPointers = pContextPointers; + } + + CodeManState codeManState; + codeManState.dwIsSet = 0; + + DWORD ControlPc = pContextRecord->Eip; + + EECodeInfo codeInfo; + codeInfo.Init((PCODE) ControlPc); + + if (!UnwindStackFrame(&rd, &codeInfo, UpdateAllRegs, &codeManState, NULL)) + { + return FALSE; + } + + pContextRecord->ContextFlags |= CONTEXT_UNWOUND_TO_CALL; + +#define ARGUMENT_AND_SCRATCH_REGISTER(reg) if (rd.pCurrentContextPointers->reg) pContextRecord->reg = *rd.pCurrentContextPointers->reg; + ENUM_ARGUMENT_AND_SCRATCH_REGISTERS(); +#undef ARGUMENT_AND_SCRATCH_REGISTER + +#define CALLEE_SAVED_REGISTER(reg) if (rd.pCurrentContextPointers->reg) pContextRecord->reg = *rd.pCurrentContextPointers->reg; + ENUM_CALLEE_SAVED_REGISTERS(); +#undef CALLEE_SAVED_REGISTER + + pContextRecord->Esp = rd.SP - codeInfo.GetCodeManager()->GetStackParameterSize(&codeInfo); + pContextRecord->Eip = rd.ControlPC; + + return TRUE; +} + /*++ Routine Description: @@ -72,42 +115,13 @@ OOPStackUnwinderX86::VirtualUnwind( *HandlerRoutine = NULL; } - REGDISPLAY rd; - - FillRegDisplay(&rd, ContextRecord); - - rd.SP = ContextRecord->Esp; - rd.PCTAddr = (UINT_PTR)&(ContextRecord->Eip); - - if (ContextPointers) - { - rd.pCurrentContextPointers = ContextPointers; - } - - CodeManState codeManState; - codeManState.dwIsSet = 0; + _ASSERTE(ContextRecord->Eip == ControlPc); - EECodeInfo codeInfo; - codeInfo.Init((PCODE) ControlPc); - - if (!UnwindStackFrame(&rd, &codeInfo, UpdateAllRegs, &codeManState, NULL)) + if (!OOPStackUnwinderX86::Unwind(ContextRecord, ContextPointers)) { return HRESULT_FROM_WIN32(ERROR_READ_FAULT); } - ContextRecord->ContextFlags |= CONTEXT_UNWOUND_TO_CALL; - -#define ARGUMENT_AND_SCRATCH_REGISTER(reg) if (rd.pCurrentContextPointers->reg) ContextRecord->reg = *rd.pCurrentContextPointers->reg; - ENUM_ARGUMENT_AND_SCRATCH_REGISTERS(); -#undef ARGUMENT_AND_SCRATCH_REGISTER - -#define CALLEE_SAVED_REGISTER(reg) if (rd.pCurrentContextPointers->reg) ContextRecord->reg = *rd.pCurrentContextPointers->reg; - ENUM_CALLEE_SAVED_REGISTERS(); -#undef CALLEE_SAVED_REGISTER - - ContextRecord->Esp = rd.SP - codeInfo.GetCodeManager()->GetStackParameterSize(&codeInfo); - ContextRecord->Eip = rd.ControlPC; - // For x86, the value of Establisher Frame Pointer is Caller SP // // (Please refers to CLR ABI for details) @@ -115,6 +129,18 @@ OOPStackUnwinderX86::VirtualUnwind( return S_OK; } +BOOL DacUnwindStackFrame(T_CONTEXT* pContextRecord, T_KNONVOLATILE_CONTEXT_POINTERS* pContextPointers) +{ + BOOL res = OOPStackUnwinderX86::Unwind(pContextRecord, NULL); + + if (res && pContextPointers) + { + FillContextPointers(pContextPointers, pContextRecord); + } + + return res; +} + //--------------------------------------------------------------------------------------- // // This function behaves like the RtlVirtualUnwind in Windows. diff --git a/src/unwinder/i386/unwinder_i386.h b/src/unwinder/i386/unwinder_i386.h index bed30bf..f29248f 100644 --- a/src/unwinder/i386/unwinder_i386.h +++ b/src/unwinder/i386/unwinder_i386.h @@ -18,6 +18,8 @@ class OOPStackUnwinderX86 : public OOPStackUnwinder { public: + static BOOL Unwind(T_CONTEXT* pContextRecord, T_KNONVOLATILE_CONTEXT_POINTERS* pContextPointers); + static HRESULT VirtualUnwind(__in DWORD HandlerType, __in DWORD ImageBase, __in DWORD ControlPc, -- 2.7.4