diff options
Diffstat (limited to 'src/debug/di/rsregsetcommon.cpp')
-rw-r--r-- | src/debug/di/rsregsetcommon.cpp | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/src/debug/di/rsregsetcommon.cpp b/src/debug/di/rsregsetcommon.cpp new file mode 100644 index 0000000000..1a2c57f63f --- /dev/null +++ b/src/debug/di/rsregsetcommon.cpp @@ -0,0 +1,248 @@ +// 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. +//***************************************************************************** +// File: RSRegSetCommon.cpp +// + +// Common cross-platform behavior of reg sets. +// Platform specific stuff is in CordbRegisterSet.cpp located in +// the platform sub-dir. +// +//***************************************************************************** +#include "stdafx.h" +#include "primitives.h" + +/* ------------------------------------------------------------------------- * + * Common (cross-platform) Register-Set stuff + * ------------------------------------------------------------------------- */ + + +CordbRegisterSet::CordbRegisterSet( + DebuggerREGDISPLAY * pRegDisplay, + CordbThread * pThread, + bool fActive, + bool fQuickUnwind, + bool fTakeOwnershipOfDRD /*= false*/) + : CordbBase(pThread->GetProcess(), 0, enumCordbRegisterSet) +{ + _ASSERTE( pRegDisplay != NULL ); + _ASSERTE( pThread != NULL ); + m_rd = pRegDisplay; + m_thread = pThread; + m_active = fActive; + m_quickUnwind = fQuickUnwind; + + m_fTakeOwnershipOfDRD = fTakeOwnershipOfDRD; + + // Add to our parent thread's neuter list. + + HRESULT hr = S_OK; + EX_TRY + { + pThread->GetRefreshStackNeuterList()->Add(GetProcess(), this); + } + EX_CATCH_HRESULT(hr); + SetUnrecoverableIfFailed(GetProcess(), hr); +} + +void CordbRegisterSet::Neuter() +{ + m_thread = NULL; + if (m_fTakeOwnershipOfDRD) + { + delete m_rd; + } + m_rd = NULL; + + CordbBase::Neuter(); +} + +CordbRegisterSet::~CordbRegisterSet() +{ + _ASSERTE(this->IsNeutered()); +} + + +HRESULT CordbRegisterSet::QueryInterface(REFIID riid, void **ppInterface) +{ + // <NOTE> + // This is an exception to the rule that a QI for a higher version API should fail if + // the debugger does not support that version of the API. The reasoning is that + // while higher versions of other APIs support enhanced functionality and are not + // required, this particular API is required on IA64. An example scenario is when an + // Everett debuggger is ported to Whidbey and the user wants to use the debugger on IA64. + // The user should not be required to implement the ICorDebugManagedCallback2 API, as would + // be the case if we make the versioning check like other higher version APIs. + // </NOTE> + if (riid == IID_ICorDebugRegisterSet) + { + *ppInterface = static_cast<ICorDebugRegisterSet*>(this); + } + else if (riid == IID_ICorDebugRegisterSet2) + { + *ppInterface = static_cast<ICorDebugRegisterSet2*>(this); + } + else if (riid == IID_IUnknown) + { + *ppInterface = static_cast<IUnknown*>(static_cast<ICorDebugRegisterSet*>(this)); + } + else + { + *ppInterface = NULL; + return E_NOINTERFACE; + } + + ExternalAddRef(); + return S_OK; +} + +//----------------------------------------------------------------------------- +// This is just a convenience function to convert a regdisplay into a Context. +// Since a context has more info than a regdisplay, the conversion isn't perfect +// and the context can't be fully accurate. +// +// Inputs: +// contextSize - sizeof incoming context buffer in bytes +// context - buffer to copy this regdisplay's OS CONTEXT structure into. +// +// Returns S_OK on success. +//----------------------------------------------------------------------------- +HRESULT CordbRegisterSet::GetThreadContext(ULONG32 contextSize, BYTE context[]) +{ + PUBLIC_REENTRANT_API_ENTRY(this); + FAIL_IF_NEUTERED(this); + ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess()); + + HRESULT hr = S_OK; + EX_TRY + { + _ASSERTE( m_thread != NULL ); + if( contextSize < sizeof( DT_CONTEXT )) + { + ThrowHR(E_INVALIDARG); + } + + ValidateOrThrow(context); + + DT_CONTEXT *pInputContext = reinterpret_cast<DT_CONTEXT *> (context); + + // Just to be safe, zero out the buffer we got in while preserving the ContextFlags. + // On X64 the ContextFlags field is not the first 4 bytes of the DT_CONTEXT. + DWORD dwContextFlags = pInputContext->ContextFlags; + ZeroMemory(context, contextSize); + pInputContext->ContextFlags = dwContextFlags; + + // Augment the leafmost (active) register w/ information from the current context. + DT_CONTEXT * pLeafContext = NULL; + if (m_active) + { + EX_TRY + { + // This may fail, but it is not a disastrous failure in this case. All we care is whether + // pLeafContext is updated to a non-NULL value. + m_thread->GetManagedContext( &pLeafContext); + } + EX_CATCH + { + } + EX_END_CATCH(SwallowAllExceptions) + + if (pLeafContext != NULL) + { + // @todo - shouldn't this be a context-flags sensitive copy? + memmove( pInputContext, pLeafContext, sizeof( DT_CONTEXT) ); + } + } + + + // Now update the registers based on the current frame. + // This is a very platform specific action. + InternalCopyRDToContext(pInputContext); + } + EX_CATCH_HRESULT(hr); + return hr; +} + +//----------------------------------------------------------------------------- +// Helpers to impl IRegSet2 on top of original IRegSet. +// These are useful on platforms that don't need IRegSet2 (like x86 + amd64). +// See CorDebug.idl for details. +// +// Inputs: +// regCount - size of pAvailable buffer in bytes +// pAvailable - buffer to hold bitvector of available registers. +// On success, bit at position CorDebugRegister is 1 iff that +// register is available. +// Returns S_OK on success. +//----------------------------------------------------------------------------- +HRESULT CordbRegisterSet::GetRegistersAvailableAdapter( + ULONG32 regCount, + BYTE pAvailable[]) +{ + // Defer to call on v1.0 interface + HRESULT hr = S_OK; + + if (regCount < sizeof(ULONG64)) + { + return E_INVALIDARG; + } + + _ASSERTE(pAvailable != NULL); + + ULONG64 availRegs; + hr = this->GetRegistersAvailable(&availRegs); + if (FAILED(hr)) + { + return hr; + } + + // Nor marshal our 64-bit value into the outgoing byte array. + for(int iBit = 0; iBit < (int) sizeof(availRegs) * 8; iBit++) + { + ULONG64 test = SETBITULONG64(iBit); + if (availRegs & test) + { + SET_BIT_MASK(pAvailable, iBit); + } + else + { + RESET_BIT_MASK(pAvailable, iBit); + } + } + return S_OK; +} + +//----------------------------------------------------------------------------- +// Helpers to impl IRegSet2 on top of original IRegSet. +// These are useful on platforms that don't need IRegSet2 (like x86 + amd64). +// See CorDebug.idl for details. +// +// Inputs: +// maskCount - size of mask buffer in bytes. +// mask - input buffer specifying registers to request +// regCount - size of regBuffer in bytes +// regBuffer - output buffer, regBuffer[n] = value of register at n-th active +// bit in mask. +// Returns S_OK on success. +//----------------------------------------------------------------------------- + +// mask input requrest registers, which get written to regCount buffer. +HRESULT CordbRegisterSet::GetRegistersAdapter( + ULONG32 maskCount, BYTE mask[], + ULONG32 regCount, CORDB_REGISTER regBuffer[]) +{ + // Convert input mask to orig mask. + ULONG64 maskOrig = 0; + + for(UINT iBit = 0; iBit < maskCount * 8; iBit++) + { + if (IS_SET_BIT_MASK(mask, iBit)) + { + maskOrig |= SETBITULONG64(iBit); + } + } + + return this->GetRegisters(maskOrig, + regCount, regBuffer); +} |