diff options
author | Jonghyun Park <parjong@gmail.com> | 2017-01-18 18:45:09 +0900 |
---|---|---|
committer | Jan Vorlicek <janvorli@microsoft.com> | 2017-01-18 10:45:09 +0100 |
commit | 009697370b7dd9a155601842360633d2fd2ba286 (patch) | |
tree | 75b1bf139b101383a4c80ad87917cca615c2338a /src/unwinder | |
parent | 1f8cfb92e098fd4e132d94bd5bdb12dca1d6e911 (diff) | |
download | coreclr-009697370b7dd9a155601842360633d2fd2ba286.tar.gz coreclr-009697370b7dd9a155601842360633d2fd2ba286.tar.bz2 coreclr-009697370b7dd9a155601842360633d2fd2ba286.zip |
[x86/Linux] Port RtlVirtualUnwind (#8911)
* [x86/Linux] (Partially) port RtlVirtualUnwind
* Rewrite x86 Unwinder using UnwindStackFrame
* Extract UnwindStackFrame from EECodeManager
* Port 'InlinedCallFrame::UpdateRegDisplay'
Diffstat (limited to 'src/unwinder')
-rw-r--r-- | src/unwinder/CMakeLists.txt | 10 | ||||
-rw-r--r-- | src/unwinder/i386/unwinder_i386.cpp | 205 | ||||
-rw-r--r-- | src/unwinder/i386/unwinder_i386.h | 33 |
3 files changed, 242 insertions, 6 deletions
diff --git a/src/unwinder/CMakeLists.txt b/src/unwinder/CMakeLists.txt index bf1cfa2938..5cd7bae337 100644 --- a/src/unwinder/CMakeLists.txt +++ b/src/unwinder/CMakeLists.txt @@ -12,12 +12,10 @@ set(UNWINDER_SOURCES ) # Include platform specific unwinder for applicable (native and cross-target) builds. -if(NOT DEFINED CLR_CMAKE_TARGET_ARCH_I386) - include_directories(${ARCH_SOURCES_DIR}) - list(APPEND UNWINDER_SOURCES - ${ARCH_SOURCES_DIR}/unwinder_${ARCH_SOURCES_DIR}.cpp - ) -endif() +include_directories(${ARCH_SOURCES_DIR}) +list(APPEND UNWINDER_SOURCES + ${ARCH_SOURCES_DIR}/unwinder_${ARCH_SOURCES_DIR}.cpp +) convert_to_absolute_path(UNWINDER_SOURCES ${UNWINDER_SOURCES}) diff --git a/src/unwinder/i386/unwinder_i386.cpp b/src/unwinder/i386/unwinder_i386.cpp new file mode 100644 index 0000000000..8d2ea53793 --- /dev/null +++ b/src/unwinder/i386/unwinder_i386.cpp @@ -0,0 +1,205 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// + +#include "stdafx.h" +#include "unwinder_i386.h" + +#ifdef WIN64EXCEPTIONS +/*++ + +Routine Description: + + This function virtually unwinds the specified function by executing its + prologue code backward or its epilogue code forward. + + If a context pointers record is specified, then the address where each + nonvolatile registers is restored from is recorded in the appropriate + element of the context pointers record. + +Arguments: + + HandlerType - Supplies the handler type expected for the virtual unwind. + This may be either an exception or an unwind handler. A flag may + optionally be supplied to avoid epilogue detection if it is known + the specified control PC is not located inside a function epilogue. + + ImageBase - Supplies the base address of the image that contains the + function being unwound. + + ControlPc - Supplies the address where control left the specified + function. + + FunctionEntry - Supplies the address of the function table entry for the + specified function. + + ContextRecord - Supplies the address of a context record. + + + HandlerData - Supplies a pointer to a variable that receives a pointer + the the language handler data. + + EstablisherFrame - Supplies a pointer to a variable that receives the + the establisher frame pointer value. + + ContextPointers - Supplies an optional pointer to a context pointers + record. + + HandlerRoutine - Supplies an optional pointer to a variable that receives + the handler routine address. If control did not leave the specified + function in either the prologue or an epilogue and a handler of the + proper type is associated with the function, then the address of the + language specific exception handler is returned. Otherwise, NULL is + returned. +--*/ +HRESULT +OOPStackUnwinderX86::VirtualUnwind( + __in DWORD HandlerType, + __in DWORD ImageBase, + __in DWORD ControlPc, + __in _PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry, + __inout PCONTEXT ContextRecord, + __out PVOID *HandlerData, + __out PDWORD EstablisherFrame, + __inout_opt PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, + __deref_opt_out_opt PEXCEPTION_ROUTINE *HandlerRoutine + ) +{ + *EstablisherFrame = ContextRecord->Esp; + if (HandlerRoutine != NULL) + { + *HandlerRoutine = NULL; + } + + REGDISPLAY rd; + + if (ContextPointers != NULL) + { +#define CALLEE_SAVED_REGISTER(reg) rd.p##reg = ContextPointers->reg; + ENUM_CALLEE_SAVED_REGISTERS(); +#undef CALLEE_SAVED_REGISTER + } + else + { +#define CALLEE_SAVED_REGISTER(reg) rd.p##reg = NULL; + ENUM_CALLEE_SAVED_REGISTERS(); +#undef CALLEE_SAVED_REGISTER + } + + if (rd.pEbp == NULL) + { + rd.pEbp = &(ContextRecord->Ebp); + } + rd.Esp = ContextRecord->Esp; + rd.ControlPC = (PCODE)(ContextRecord->Eip); + rd.PCTAddr = (UINT_PTR)&(ContextRecord->Eip); + + CodeManState codeManState; + codeManState.dwIsSet = 0; + + EECodeInfo codeInfo; + codeInfo.Init((PCODE) ControlPc); + + if (!UnwindStackFrame(&rd, &codeInfo, UpdateAllRegs, &codeManState, NULL)) + { + return HRESULT_FROM_WIN32(ERROR_READ_FAULT); + } + +#define CALLEE_SAVED_REGISTER(reg) if (rd.p##reg != NULL) { ContextRecord->reg = *rd.p##reg; } + ENUM_CALLEE_SAVED_REGISTERS(); +#undef CALLEE_SAVED_REGISTER + + if (ContextPointers != NULL) + { +#define CALLEE_SAVED_REGISTER(reg) if (rd.p##reg != &(ContextRecord->reg)) { ContextPointers->reg = rd.p##reg; } + ENUM_CALLEE_SAVED_REGISTERS(); +#undef CALLEE_SAVED_REGISTER + } + + ContextRecord->Esp = rd.Esp; + ContextRecord->Eip = rd.ControlPC; + ContextRecord->Ebp = *rd.pEbp; + + return S_OK; +} + +//--------------------------------------------------------------------------------------- +// +// This function behaves like the RtlVirtualUnwind in Windows. +// It virtually unwinds the specified function by executing its +// prologue code backward or its epilogue code forward. +// +// If a context pointers record is specified, then the address where each +// nonvolatile registers is restored from is recorded in the appropriate +// element of the context pointers record. +// +// Arguments: +// +// HandlerType - Supplies the handler type expected for the virtual unwind. +// This may be either an exception or an unwind handler. A flag may +// optionally be supplied to avoid epilogue detection if it is known +// the specified control PC is not located inside a function epilogue. +// +// ImageBase - Supplies the base address of the image that contains the +// function being unwound. +// +// ControlPc - Supplies the address where control left the specified +// function. +// +// FunctionEntry - Supplies the address of the function table entry for the +// specified function. +// +// ContextRecord - Supplies the address of a context record. +// +// HandlerData - Supplies a pointer to a variable that receives a pointer +// the the language handler data. +// +// EstablisherFrame - Supplies a pointer to a variable that receives the +// the establisher frame pointer value. +// +// ContextPointers - Supplies an optional pointer to a context pointers +// record. +// +// Return value: +// +// The handler routine address. If control did not leave the specified +// function in either the prologue or an epilogue and a handler of the +// proper type is associated with the function, then the address of the +// language specific exception handler is returned. Otherwise, NULL is +// returned. +// +EXTERN_C +NTSYSAPI +PEXCEPTION_ROUTINE +NTAPI +RtlVirtualUnwind ( + __in DWORD HandlerType, + __in DWORD ImageBase, + __in DWORD ControlPc, + __in PRUNTIME_FUNCTION FunctionEntry, + __inout PT_CONTEXT ContextRecord, + __out PVOID *HandlerData, + __out PDWORD EstablisherFrame, + __inout_opt PT_KNONVOLATILE_CONTEXT_POINTERS ContextPointers + ) +{ + PEXCEPTION_ROUTINE handlerRoutine; + + HRESULT res = OOPStackUnwinderX86::VirtualUnwind( + HandlerType, + ImageBase, + ControlPc, + (_PIMAGE_RUNTIME_FUNCTION_ENTRY)FunctionEntry, + ContextRecord, + HandlerData, + EstablisherFrame, + ContextPointers, + &handlerRoutine); + + _ASSERTE(SUCCEEDED(res)); + + return handlerRoutine; +} +#endif // WIN64EXCEPTIONS diff --git a/src/unwinder/i386/unwinder_i386.h b/src/unwinder/i386/unwinder_i386.h new file mode 100644 index 0000000000..bed30bf894 --- /dev/null +++ b/src/unwinder/i386/unwinder_i386.h @@ -0,0 +1,33 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +// + +#ifndef __unwinder_i386_h__ +#define __unwinder_i386_h__ + +#include "unwinder.h" + +#ifdef WIN64EXCEPTIONS +//--------------------------------------------------------------------------------------- +// +// See the comment for the base class code:OOPStackUnwinder. +// + +class OOPStackUnwinderX86 : public OOPStackUnwinder +{ +public: + static HRESULT VirtualUnwind(__in DWORD HandlerType, + __in DWORD ImageBase, + __in DWORD ControlPc, + __in _PIMAGE_RUNTIME_FUNCTION_ENTRY FunctionEntry, + __inout PCONTEXT ContextRecord, + __out PVOID *HandlerData, + __out PDWORD EstablisherFrame, + __inout_opt PKNONVOLATILE_CONTEXT_POINTERS ContextPointers, + __deref_opt_out_opt PEXCEPTION_ROUTINE *HandlerRoutine); +}; +#endif // WIN64EXCEPTIONS + +#endif // __unwinder_i386_h__ |