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
21CordbRegisterSet::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
49void 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
61CordbRegisterSet::~CordbRegisterSet()
62{
63 _ASSERTE(this->IsNeutered());
64}
65
66
67HRESULT 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//-----------------------------------------------------------------------------
111HRESULT 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//-----------------------------------------------------------------------------
179HRESULT 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.
231HRESULT 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}
249