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 | } |
249 | |