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//
27DataTargetAdapter::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//
39DataTargetAdapter::~DataTargetAdapter()
40{
41 m_pLegacyTarget->Release();
42}
43
44// Standard impl of IUnknown::QueryInterface
45HRESULT STDMETHODCALLTYPE
46DataTargetAdapter::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
76ULONG STDMETHODCALLTYPE
77DataTargetAdapter::AddRef()
78{
79 LONG ref = InterlockedIncrement(&m_ref);
80 return ref;
81}
82
83// Standard impl of IUnknown::Release
84ULONG STDMETHODCALLTYPE
85DataTargetAdapter::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
97HRESULT STDMETHODCALLTYPE
98DataTargetAdapter::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
186HRESULT STDMETHODCALLTYPE
187DataTargetAdapter::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
199HRESULT STDMETHODCALLTYPE
200DataTargetAdapter::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
226HRESULT STDMETHODCALLTYPE
227DataTargetAdapter::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
238HRESULT STDMETHODCALLTYPE
239DataTargetAdapter::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
249HRESULT STDMETHODCALLTYPE
250DataTargetAdapter::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