// 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) { // // 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. // if (riid == IID_ICorDebugRegisterSet) { *ppInterface = static_cast(this); } else if (riid == IID_ICorDebugRegisterSet2) { *ppInterface = static_cast(this); } else if (riid == IID_IUnknown) { *ppInterface = static_cast(static_cast(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 (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); }