Merge pull request #10073 from adityamandaleeka/handle_types_to_enum_1
[platform/upstream/coreclr.git] / src / debug / di / rsregsetcommon.cpp
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 //*****************************************************************************
5 // File: RSRegSetCommon.cpp
6 // 
7
8 // Common cross-platform behavior of reg sets.
9 // Platform specific stuff is in CordbRegisterSet.cpp located in
10 // the platform sub-dir.
11 //
12 //*****************************************************************************
13 #include "stdafx.h"
14 #include "primitives.h"
15
16 /* ------------------------------------------------------------------------- *
17  * Common (cross-platform) Register-Set stuff
18  * ------------------------------------------------------------------------- */
19
20
21 CordbRegisterSet::CordbRegisterSet( 
22     DebuggerREGDISPLAY * pRegDisplay, 
23     CordbThread *        pThread,
24     bool fActive, 
25     bool fQuickUnwind,
26     bool fTakeOwnershipOfDRD /*= false*/)
27   : CordbBase(pThread->GetProcess(), 0, enumCordbRegisterSet)
28 {
29     _ASSERTE( pRegDisplay != NULL );
30     _ASSERTE( pThread != NULL );
31     m_rd          = pRegDisplay;
32     m_thread      = pThread;
33     m_active      = fActive;
34     m_quickUnwind = fQuickUnwind;
35
36     m_fTakeOwnershipOfDRD = fTakeOwnershipOfDRD;
37
38     // Add to our parent thread's neuter list.
39     
40     HRESULT hr = S_OK;
41     EX_TRY
42     {
43         pThread->GetRefreshStackNeuterList()->Add(GetProcess(), this);
44     } 
45     EX_CATCH_HRESULT(hr);
46     SetUnrecoverableIfFailed(GetProcess(), hr);
47 }
48
49 void CordbRegisterSet::Neuter()
50 {
51     m_thread = NULL;
52     if (m_fTakeOwnershipOfDRD)
53     {
54         delete m_rd;
55     }
56     m_rd = NULL;
57     
58     CordbBase::Neuter();
59 }
60
61 CordbRegisterSet::~CordbRegisterSet()
62 {
63     _ASSERTE(this->IsNeutered());
64 }
65
66
67 HRESULT CordbRegisterSet::QueryInterface(REFIID riid, void **ppInterface)
68 {
69     // <NOTE>
70     // This is an exception to the rule that a QI for a higher version API should fail if
71     // the debugger does not support that version of the API.  The reasoning is that
72     // while higher versions of other APIs support enhanced functionality and are not
73     // required, this particular API is required on IA64.  An example scenario is when an
74     // Everett debuggger is ported to Whidbey and the user wants to use the debugger on IA64.
75     // The user should not be required to implement the ICorDebugManagedCallback2 API, as would
76     // be the case if we make the versioning check like other higher version APIs.
77     // </NOTE>
78     if (riid == IID_ICorDebugRegisterSet)
79     {
80         *ppInterface = static_cast<ICorDebugRegisterSet*>(this);
81     }
82     else if (riid == IID_ICorDebugRegisterSet2)
83     {
84         *ppInterface = static_cast<ICorDebugRegisterSet2*>(this);
85     }
86     else if (riid == IID_IUnknown)
87     {
88         *ppInterface = static_cast<IUnknown*>(static_cast<ICorDebugRegisterSet*>(this));
89     }
90     else
91     {
92         *ppInterface = NULL;
93         return E_NOINTERFACE;
94     }
95
96     ExternalAddRef();
97     return S_OK;
98 }
99
100 //-----------------------------------------------------------------------------
101 // This is just a convenience function to convert a regdisplay into a Context.
102 // Since a context has more info than a regdisplay, the conversion isn't perfect
103 // and the context can't be fully accurate.
104 //
105 // Inputs:
106 //    contextSize - sizeof incoming context buffer  in bytes
107 //    context - buffer to copy this regdisplay's OS CONTEXT structure into.
108 //
109 // Returns S_OK on success. 
110 //-----------------------------------------------------------------------------
111 HRESULT CordbRegisterSet::GetThreadContext(ULONG32 contextSize, BYTE context[])
112 {
113     PUBLIC_REENTRANT_API_ENTRY(this);
114     FAIL_IF_NEUTERED(this);
115     ATT_REQUIRE_STOPPED_MAY_FAIL(GetProcess());
116
117     HRESULT hr = S_OK;
118     EX_TRY
119     {
120         _ASSERTE( m_thread != NULL );
121         if( contextSize < sizeof( DT_CONTEXT ))
122         {
123             ThrowHR(E_INVALIDARG);
124         }        
125
126         ValidateOrThrow(context);
127
128         DT_CONTEXT *pInputContext = reinterpret_cast<DT_CONTEXT *> (context);
129         
130         // Just to be safe, zero out the buffer we got in while preserving the ContextFlags.  
131         // On X64 the ContextFlags field is not the first 4 bytes of the DT_CONTEXT.
132         DWORD dwContextFlags = pInputContext->ContextFlags;
133         ZeroMemory(context, contextSize);
134         pInputContext->ContextFlags = dwContextFlags;
135
136         // Augment the leafmost (active) register w/ information from the current context.
137         DT_CONTEXT * pLeafContext = NULL;
138         if (m_active)
139         {
140             EX_TRY
141             {
142                 // This may fail, but it is not a disastrous failure in this case.  All we care is whether
143                 // pLeafContext is updated to a non-NULL value.
144                 m_thread->GetManagedContext( &pLeafContext);
145             }
146             EX_CATCH
147             {
148             }
149             EX_END_CATCH(SwallowAllExceptions)
150
151             if (pLeafContext != NULL)
152             {
153                 // @todo - shouldn't this be a context-flags sensitive copy?
154                 memmove( pInputContext, pLeafContext, sizeof( DT_CONTEXT) );
155             }
156         }
157
158
159         // Now update the registers based on the current frame.
160         // This is a very platform specific action.
161         InternalCopyRDToContext(pInputContext);
162     }
163     EX_CATCH_HRESULT(hr);
164     return hr;
165 }
166
167 //-----------------------------------------------------------------------------
168 // Helpers to impl IRegSet2 on top of original IRegSet.
169 // These are useful on platforms that don't need IRegSet2 (like x86 + amd64). 
170 // See CorDebug.idl for details.
171 //
172 // Inputs:
173 //   regCount - size of pAvailable buffer in bytes
174 //   pAvailable - buffer to hold bitvector of available registers. 
175 //                On success, bit at position CorDebugRegister is 1 iff that
176 //                register is available.
177 // Returns S_OK on success.
178 //-----------------------------------------------------------------------------
179 HRESULT CordbRegisterSet::GetRegistersAvailableAdapter(
180     ULONG32 regCount, 
181     BYTE    pAvailable[])
182 {
183     // Defer to call on v1.0 interface
184     HRESULT hr = S_OK;
185
186     if (regCount < sizeof(ULONG64))
187     {
188         return E_INVALIDARG;
189     }
190
191     _ASSERTE(pAvailable != NULL);
192
193     ULONG64 availRegs;
194     hr = this->GetRegistersAvailable(&availRegs);
195     if (FAILED(hr))
196     {
197         return hr;
198     }
199
200     // Nor marshal our 64-bit value into the outgoing byte array.
201     for(int iBit = 0; iBit < (int) sizeof(availRegs) * 8; iBit++)
202     {
203         ULONG64 test = SETBITULONG64(iBit);
204         if (availRegs & test)
205         {
206             SET_BIT_MASK(pAvailable, iBit);
207         }
208         else
209         {
210             RESET_BIT_MASK(pAvailable, iBit);
211         }
212     }
213     return S_OK;
214 }
215
216 //-----------------------------------------------------------------------------
217 // Helpers to impl IRegSet2 on top of original IRegSet.
218 // These are useful on platforms that don't need IRegSet2 (like x86 + amd64). 
219 // See CorDebug.idl for details.
220 //
221 // Inputs:
222 //  maskCount - size of mask buffer in bytes.
223 //  mask - input buffer specifying registers to request
224 //  regCount - size of regBuffer in bytes
225 //  regBuffer - output buffer, regBuffer[n] = value of register at n-th active
226 //              bit in mask.
227 // Returns S_OK on success.
228 //-----------------------------------------------------------------------------
229
230 // mask input requrest registers, which get written to regCount buffer.
231 HRESULT CordbRegisterSet::GetRegistersAdapter(
232     ULONG32 maskCount, BYTE mask[], 
233     ULONG32 regCount, CORDB_REGISTER regBuffer[])
234 {
235     // Convert input mask to orig mask.
236     ULONG64 maskOrig = 0;
237
238     for(UINT iBit = 0; iBit < maskCount * 8; iBit++)
239     {
240         if (IS_SET_BIT_MASK(mask, iBit))
241         {
242             maskOrig |= SETBITULONG64(iBit);
243         }
244     }
245     
246     return this->GetRegisters(maskOrig, 
247         regCount, regBuffer);
248 }