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 | // DataTargetAdapter.cpp |
6 | // |
7 | |
8 | // |
9 | // implementation of compatibility adapter for ICLRDataTarget |
10 | //***************************************************************************** |
11 | |
12 | #include "stdafx.h" |
13 | #include "datatargetadapter.h" |
14 | #include <clrdata.h> |
15 | #include "dacimpl.h" |
16 | |
17 | #ifndef IMAGE_FILE_MACHINE_ARM64 |
18 | #define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian |
19 | #endif |
20 | |
21 | // |
22 | // DataTargetAdaptor ctor |
23 | // |
24 | // Instantiate a DataTargetAdapter over the supplied legacy DataTarget interface. |
25 | // Takes a ref on the supplied interface and releases it in our dtor. |
26 | // |
27 | DataTargetAdapter::DataTargetAdapter(ICLRDataTarget * pLegacyTarget) : |
28 | m_ref(0), |
29 | m_pLegacyTarget(pLegacyTarget) |
30 | { |
31 | m_pLegacyTarget->AddRef(); |
32 | } |
33 | |
34 | // |
35 | // DataTargetAdapter dtor |
36 | // |
37 | // Releases the underlying DataTarget interface |
38 | // |
39 | DataTargetAdapter::~DataTargetAdapter() |
40 | { |
41 | m_pLegacyTarget->Release(); |
42 | } |
43 | |
44 | // Standard impl of IUnknown::QueryInterface |
45 | HRESULT STDMETHODCALLTYPE |
46 | DataTargetAdapter::QueryInterface( |
47 | REFIID interfaceId, |
48 | PVOID* pInterface) |
49 | { |
50 | if (interfaceId == IID_IUnknown) |
51 | { |
52 | *pInterface = static_cast<IUnknown *>(static_cast<ICorDebugDataTarget *>(this)); |
53 | } |
54 | else if (interfaceId == IID_ICorDebugDataTarget) |
55 | { |
56 | *pInterface = static_cast<ICorDebugDataTarget *>(this); |
57 | } |
58 | else if (interfaceId == IID_ICorDebugMutableDataTarget) |
59 | { |
60 | // Note that we always implement the mutable interface, even though our underlying target |
61 | // may return E_NOTIMPL for all the functions on this interface. There is no reliable way |
62 | // to tell apriori whether an ICLRDataTarget instance supports writing or not. |
63 | *pInterface = static_cast<ICorDebugMutableDataTarget *>(this); |
64 | } |
65 | else |
66 | { |
67 | // For ICorDebugDataTarget4 and other interfaces directly implemented by the legacy data target. |
68 | return m_pLegacyTarget->QueryInterface(interfaceId, pInterface); |
69 | } |
70 | |
71 | AddRef(); |
72 | return S_OK; |
73 | } |
74 | |
75 | // Standard impl of IUnknown::AddRef |
76 | ULONG STDMETHODCALLTYPE |
77 | DataTargetAdapter::AddRef() |
78 | { |
79 | LONG ref = InterlockedIncrement(&m_ref); |
80 | return ref; |
81 | } |
82 | |
83 | // Standard impl of IUnknown::Release |
84 | ULONG STDMETHODCALLTYPE |
85 | DataTargetAdapter::Release() |
86 | { |
87 | SUPPORTS_DAC_HOST_ONLY; |
88 | LONG ref = InterlockedDecrement(&m_ref); |
89 | if (ref == 0) |
90 | { |
91 | delete this; |
92 | } |
93 | return ref; |
94 | } |
95 | |
96 | // impl of interface method ICorDebugDataTarget::GetPlatform |
97 | HRESULT STDMETHODCALLTYPE |
98 | DataTargetAdapter::GetPlatform( |
99 | CorDebugPlatform * pPlatform) |
100 | { |
101 | SUPPORTS_DAC_HOST_ONLY; |
102 | |
103 | // Get the target machine type, and assume it's Windows |
104 | HRESULT hr; |
105 | |
106 | ULONG32 ulMachineType; |
107 | IfFailRet(m_pLegacyTarget->GetMachineType(&ulMachineType)); |
108 | |
109 | ULONG32 ulExpectedPointerSize; |
110 | CorDebugPlatform platform; |
111 | |
112 | switch(ulMachineType) |
113 | { |
114 | #ifdef FEATURE_PAL |
115 | case IMAGE_FILE_MACHINE_I386: |
116 | ulExpectedPointerSize = 4; |
117 | platform = CORDB_PLATFORM_POSIX_X86; |
118 | break; |
119 | |
120 | case IMAGE_FILE_MACHINE_AMD64: |
121 | ulExpectedPointerSize = 8; |
122 | platform = CORDB_PLATFORM_POSIX_AMD64; |
123 | break; |
124 | |
125 | case IMAGE_FILE_MACHINE_ARMNT: |
126 | ulExpectedPointerSize = 4; |
127 | platform = CORDB_PLATFORM_POSIX_ARM; |
128 | break; |
129 | |
130 | case IMAGE_FILE_MACHINE_ARM64: |
131 | ulExpectedPointerSize = 8; |
132 | platform = CORDB_PLATFORM_POSIX_ARM64; |
133 | break; |
134 | |
135 | case IMAGE_FILE_MACHINE_IA64: |
136 | _ASSERTE_MSG(false, "Not supported platform." ); |
137 | return E_NOTIMPL; |
138 | |
139 | #else // FEATURE_PAL |
140 | case IMAGE_FILE_MACHINE_I386: |
141 | ulExpectedPointerSize = 4; |
142 | platform = CORDB_PLATFORM_WINDOWS_X86; |
143 | break; |
144 | |
145 | case IMAGE_FILE_MACHINE_AMD64: |
146 | ulExpectedPointerSize = 8; |
147 | platform = CORDB_PLATFORM_WINDOWS_AMD64; |
148 | break; |
149 | |
150 | case IMAGE_FILE_MACHINE_IA64: |
151 | ulExpectedPointerSize = 8; |
152 | platform = CORDB_PLATFORM_WINDOWS_IA64; |
153 | break; |
154 | |
155 | case IMAGE_FILE_MACHINE_ARMNT: |
156 | ulExpectedPointerSize = 4; |
157 | platform = CORDB_PLATFORM_WINDOWS_ARM; |
158 | break; |
159 | |
160 | case IMAGE_FILE_MACHINE_ARM64: |
161 | ulExpectedPointerSize = 8; |
162 | platform = CORDB_PLATFORM_WINDOWS_ARM64; |
163 | break; |
164 | #endif // FEATURE_PAL |
165 | |
166 | default: |
167 | // No other platforms are current supported |
168 | return E_NOTIMPL; |
169 | } |
170 | |
171 | // Validate that the target pointer size matches |
172 | ULONG32 ulPointerSize; |
173 | IfFailRet(m_pLegacyTarget->GetPointerSize(&ulPointerSize)); |
174 | |
175 | if (ulPointerSize != ulExpectedPointerSize) |
176 | { |
177 | return E_UNEXPECTED; |
178 | } |
179 | |
180 | // Found a match |
181 | *pPlatform = platform; |
182 | return S_OK; |
183 | } |
184 | |
185 | // impl of interface method ICorDebugDataTarget::ReadVirtual |
186 | HRESULT STDMETHODCALLTYPE |
187 | DataTargetAdapter::ReadVirtual( |
188 | CORDB_ADDRESS address, |
189 | PBYTE pBuffer, |
190 | ULONG32 cbRequestSize, |
191 | ULONG32 * pcbRead) |
192 | { |
193 | SUPPORTS_DAC_HOST_ONLY; |
194 | CLRDATA_ADDRESS cdAddr = TO_CDADDR(address); |
195 | return m_pLegacyTarget->ReadVirtual(cdAddr, pBuffer, cbRequestSize, pcbRead); |
196 | } |
197 | |
198 | // impl of interface method ICorDebugMutableDataTarget::WriteVirtual |
199 | HRESULT STDMETHODCALLTYPE |
200 | DataTargetAdapter::WriteVirtual( |
201 | CORDB_ADDRESS address, |
202 | const BYTE * pBuffer, |
203 | ULONG32 cbRequestSize) |
204 | { |
205 | SUPPORTS_DAC_HOST_ONLY; |
206 | CLRDATA_ADDRESS cdAddr = TO_CDADDR(address); |
207 | ULONG32 cbWritten = 0; |
208 | HRESULT hr = S_OK; |
209 | |
210 | hr = m_pLegacyTarget->WriteVirtual(cdAddr, const_cast<BYTE *>(pBuffer), cbRequestSize, &cbWritten); |
211 | |
212 | if (SUCCEEDED(hr) && cbWritten != cbRequestSize) |
213 | { |
214 | // This shouldn't happen - existing data target implementations make writes atomic (eg. |
215 | // WriteProcessMemory), even though that isn't strictly required by the old interface. |
216 | // If this does happen, we technically leave the process in an inconsistent state, and we make no |
217 | // attempt to recover from that here. |
218 | _ASSERTE_MSG(false, "Legacy data target WriteVirtual partial write - target left in inconsistent state" ); |
219 | return HRESULT_FROM_WIN32(ERROR_PARTIAL_COPY); |
220 | } |
221 | return hr; |
222 | } |
223 | |
224 | |
225 | // impl of interface method ICorDebugDataTarget::GetThreadContext |
226 | HRESULT STDMETHODCALLTYPE |
227 | DataTargetAdapter::GetThreadContext( |
228 | DWORD dwThreadID, |
229 | ULONG32 contextFlags, |
230 | ULONG32 contextSize, |
231 | PBYTE pContext) |
232 | { |
233 | SUPPORTS_DAC_HOST_ONLY; |
234 | return m_pLegacyTarget->GetThreadContext(dwThreadID, contextFlags, contextSize, pContext); |
235 | } |
236 | |
237 | // impl of interface method ICorDebugMutableDataTarget::SetThreadContext |
238 | HRESULT STDMETHODCALLTYPE |
239 | DataTargetAdapter::SetThreadContext( |
240 | DWORD dwThreadID, |
241 | ULONG32 contextSize, |
242 | const BYTE * pContext) |
243 | { |
244 | SUPPORTS_DAC_HOST_ONLY; |
245 | return m_pLegacyTarget->SetThreadContext(dwThreadID, contextSize, const_cast<BYTE *>(pContext)); |
246 | } |
247 | |
248 | // implementation of ICorDebugMutableDataTarget::ContinueStatusChanged |
249 | HRESULT STDMETHODCALLTYPE |
250 | DataTargetAdapter::ContinueStatusChanged( |
251 | DWORD dwThreadId, |
252 | CORDB_CONTINUE_STATUS continueStatus) |
253 | { |
254 | SUPPORTS_DAC_HOST_ONLY; |
255 | // No corresponding API in pre-arrowhead ICLRDataTarget* interfaces. |
256 | // Note that we briefly had a ICLRDataTarget4 with this API, but this was never released outside the CLR so |
257 | // all existing implementations should now be gone. |
258 | return E_NOTIMPL; |
259 | } |
260 | |