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
6//
7// File: ShimRemoteDataTarget.cpp
8//
9//*****************************************************************************
10#include "stdafx.h"
11#include "safewrap.h"
12
13#include "check.h"
14
15#include <limits.h>
16
17#include "shimpriv.h"
18#include "shimdatatarget.h"
19
20#include "dbgtransportsession.h"
21#include "dbgtransportmanager.h"
22
23
24class ShimRemoteDataTarget : public ShimDataTarget
25{
26public:
27 ShimRemoteDataTarget(DWORD processId, DbgTransportTarget * pProxy, DbgTransportSession * pTransport);
28
29 virtual ~ShimRemoteDataTarget();
30
31 virtual void Dispose();
32
33 //
34 // ICorDebugMutableDataTarget.
35 //
36
37 virtual HRESULT STDMETHODCALLTYPE GetPlatform(
38 CorDebugPlatform *pPlatform);
39
40 virtual HRESULT STDMETHODCALLTYPE ReadVirtual(
41 CORDB_ADDRESS address,
42 BYTE * pBuffer,
43 ULONG32 request,
44 ULONG32 *pcbRead);
45
46 virtual HRESULT STDMETHODCALLTYPE WriteVirtual(
47 CORDB_ADDRESS address,
48 const BYTE * pBuffer,
49 ULONG32 request);
50
51 virtual HRESULT STDMETHODCALLTYPE GetThreadContext(
52 DWORD dwThreadID,
53 ULONG32 contextFlags,
54 ULONG32 contextSize,
55 BYTE * context);
56
57 virtual HRESULT STDMETHODCALLTYPE SetThreadContext(
58 DWORD dwThreadID,
59 ULONG32 contextSize,
60 const BYTE * context);
61
62 virtual HRESULT STDMETHODCALLTYPE ContinueStatusChanged(
63 DWORD dwThreadId,
64 CORDB_CONTINUE_STATUS dwContinueStatus);
65
66 virtual HRESULT STDMETHODCALLTYPE VirtualUnwind(
67 DWORD threadId, ULONG32 contextSize, PBYTE context);
68
69private:
70 DbgTransportTarget * m_pProxy;
71 DbgTransportSession * m_pTransport;
72};
73
74
75// Helper macro to check for failure conditions at the start of data-target methods.
76#define ReturnFailureIfStateNotOk() \
77 if (m_hr != S_OK) \
78 { \
79 return m_hr; \
80 }
81
82//---------------------------------------------------------------------------------------
83//
84// This is the ctor for ShimRemoteDataTarget.
85//
86// Arguments:
87// processId - pid of live process on the remote machine
88// pProxy - connection to the debugger proxy
89// pTransport - connection to the debuggee process
90//
91
92ShimRemoteDataTarget::ShimRemoteDataTarget(DWORD processId,
93 DbgTransportTarget * pProxy,
94 DbgTransportSession * pTransport)
95{
96 m_ref = 0;
97
98 m_processId = processId;
99 m_pProxy = pProxy;
100 m_pTransport = pTransport;
101
102 m_hr = S_OK;
103
104 m_fpContinueStatusChanged = NULL;
105 m_pContinueStatusChangedUserData = NULL;
106}
107
108//---------------------------------------------------------------------------------------
109//
110// dtor for ShimRemoteDataTarget
111//
112
113ShimRemoteDataTarget::~ShimRemoteDataTarget()
114{
115 Dispose();
116}
117
118//---------------------------------------------------------------------------------------
119//
120// Dispose all resources and neuter the object.
121//
122// Notes:
123// Release all resources (such as the connections to the debugger proxy and the debuggee process).
124// May be called multiple times.
125// All other non-trivial APIs (eg, not IUnknown) will fail after this.
126//
127
128void ShimRemoteDataTarget::Dispose()
129{
130 if (m_pTransport != NULL)
131 {
132 m_pProxy->ReleaseTransport(m_pTransport);
133 }
134
135 m_pTransport = NULL;
136 m_hr = CORDBG_E_OBJECT_NEUTERED;
137}
138
139//---------------------------------------------------------------------------------------
140//
141// Construction method for data-target
142//
143// Arguments:
144// machineInfo - (input) the IP address of the remote machine and the port number of the debugger proxy
145// processId - (input) live OS process ID to build a data-target for.
146// ppDataTarget - (output) new data-target instance. This gets addreffed.
147//
148// Return Value:
149// S_OK on success.
150//
151// Assumptions:
152// pid is for a process on the remote machine specified by the IP address in machineInfo
153// Caller must release *ppDataTarget.
154//
155
156HRESULT BuildPlatformSpecificDataTarget(MachineInfo machineInfo,
157 const ProcessDescriptor * pProcessDescriptor,
158 ShimDataTarget ** ppDataTarget)
159{
160 HandleHolder hDummy;
161 HRESULT hr = E_FAIL;
162
163 ShimRemoteDataTarget * pRemoteDataTarget = NULL;
164 DbgTransportTarget * pProxy = g_pDbgTransportTarget;
165 DbgTransportSession * pTransport = NULL;
166
167 hr = pProxy->GetTransportForProcess(pProcessDescriptor, &pTransport, &hDummy);
168 if (FAILED(hr))
169 {
170 goto Label_Exit;
171 }
172
173 if (!pTransport->WaitForSessionToOpen(10000))
174 {
175 hr = CORDBG_E_TIMEOUT;
176 goto Label_Exit;
177 }
178
179 pRemoteDataTarget = new (nothrow) ShimRemoteDataTarget(pProcessDescriptor->m_Pid, pProxy, pTransport);
180 if (pRemoteDataTarget == NULL)
181 {
182 hr = E_OUTOFMEMORY;
183 goto Label_Exit;
184 }
185
186 _ASSERTE(SUCCEEDED(hr));
187 *ppDataTarget = pRemoteDataTarget;
188 pRemoteDataTarget->AddRef(); // must addref out-parameters
189
190Label_Exit:
191 if (FAILED(hr))
192 {
193 if (pRemoteDataTarget != NULL)
194 {
195 // The ShimRemoteDataTarget has ownership of the proxy and the transport,
196 // so we don't need to clean them up here.
197 delete pRemoteDataTarget;
198 }
199 else
200 {
201 if (pTransport != NULL)
202 {
203 pProxy->ReleaseTransport(pTransport);
204 }
205 }
206 }
207
208 return hr;
209}
210
211// impl of interface method ICorDebugDataTarget::GetPlatform
212HRESULT STDMETHODCALLTYPE
213ShimRemoteDataTarget::GetPlatform(
214 CorDebugPlatform *pPlatform)
215{
216#ifdef FEATURE_PAL
217 #if defined(DBG_TARGET_X86)
218 *pPlatform = CORDB_PLATFORM_POSIX_X86;
219 #elif defined(DBG_TARGET_AMD64)
220 *pPlatform = CORDB_PLATFORM_POSIX_AMD64;
221 #elif defined(DBG_TARGET_ARM)
222 *pPlatform = CORDB_PLATFORM_POSIX_ARM;
223 #elif defined(DBG_TARGET_ARM64)
224 *pPlatform = CORDB_PLATFORM_POSIX_ARM64;
225 #else
226 #error Unknown Processor.
227 #endif
228#else
229 #if defined(DBG_TARGET_X86)
230 *pPlatform = CORDB_PLATFORM_WINDOWS_X86;
231 #elif defined(DBG_TARGET_AMD64)
232 *pPlatform = CORDB_PLATFORM_WINDOWS_AMD64;
233 #elif defined(DBG_TARGET_ARM)
234 *pPlatform = CORDB_PLATFORM_WINDOWS_ARM;
235 #elif defined(DBG_TARGET_ARM64)
236 *pPlatform = CORDB_PLATFORM_WINDOWS_ARM64;
237 #else
238 #error Unknown Processor.
239 #endif
240#endif
241
242 return S_OK;
243}
244
245// impl of interface method ICorDebugDataTarget::ReadVirtual
246HRESULT STDMETHODCALLTYPE
247ShimRemoteDataTarget::ReadVirtual(
248 CORDB_ADDRESS address,
249 PBYTE pBuffer,
250 ULONG32 cbRequestSize,
251 ULONG32 *pcbRead)
252{
253 ReturnFailureIfStateNotOk();
254
255 HRESULT hr = E_FAIL;
256 hr = m_pTransport->ReadMemory(reinterpret_cast<BYTE *>(CORDB_ADDRESS_TO_PTR(address)),
257 pBuffer,
258 cbRequestSize);
259 if (pcbRead != NULL)
260 {
261 *pcbRead = (SUCCEEDED(hr) ? cbRequestSize : 0);
262 }
263 return hr;
264}
265
266// impl of interface method ICorDebugMutableDataTarget::WriteVirtual
267HRESULT STDMETHODCALLTYPE
268ShimRemoteDataTarget::WriteVirtual(
269 CORDB_ADDRESS pAddress,
270 const BYTE * pBuffer,
271 ULONG32 cbRequestSize)
272{
273 ReturnFailureIfStateNotOk();
274
275 HRESULT hr = E_FAIL;
276 hr = m_pTransport->WriteMemory(reinterpret_cast<BYTE *>(CORDB_ADDRESS_TO_PTR(pAddress)),
277 const_cast<BYTE *>(pBuffer),
278 cbRequestSize);
279 return hr;
280}
281
282// impl of interface method ICorDebugMutableDataTarget::GetThreadContext
283HRESULT STDMETHODCALLTYPE
284ShimRemoteDataTarget::GetThreadContext(
285 DWORD dwThreadID,
286 ULONG32 contextFlags,
287 ULONG32 contextSize,
288 BYTE * pContext)
289{
290 ReturnFailureIfStateNotOk();
291
292 // GetThreadContext() is currently not implemented in ShimRemoteDataTarget, which is used with our pipe transport
293 // (FEATURE_DBGIPC_TRANSPORT_DI). Pipe transport is used on POSIX system, but occasionally we can turn it on for Windows for testing,
294 // and then we'd like to have same behavior as on POSIX system (zero context).
295 //
296 // We don't have a good way to implement GetThreadContext() in ShimRemoteDataTarget yet, because we have no way to convert a thread ID to a
297 // thread handle. The function to do the conversion is OpenThread(), which is not implemented in PAL. Even if we had a handle, PAL implementation
298 // of GetThreadContext() is very limited and doesn't work when we're not attached with ptrace.
299 // Instead, we just zero out the seed CONTEXT for the stackwalk. This tells the stackwalker to
300 // start the stackwalk with the first explicit frame. This won't work when we do native debugging,
301 // but that won't happen on the POSIX systems since they don't support native debugging.
302 ZeroMemory(pContext, contextSize);
303 return E_NOTIMPL;
304}
305
306// impl of interface method ICorDebugMutableDataTarget::SetThreadContext
307HRESULT STDMETHODCALLTYPE
308ShimRemoteDataTarget::SetThreadContext(
309 DWORD dwThreadID,
310 ULONG32 contextSize,
311 const BYTE * pContext)
312{
313 ReturnFailureIfStateNotOk();
314
315 // ICorDebugDataTarget::GetThreadContext() and ICorDebugDataTarget::SetThreadContext() are currently only
316 // required for interop-debugging and inspection of floating point registers, both of which are not
317 // implemented on Mac.
318 _ASSERTE(!"The remote data target doesn't know how to set a thread's CONTEXT.");
319 return E_NOTIMPL;
320}
321
322// Public implementation of ICorDebugMutableDataTarget::ContinueStatusChanged
323HRESULT STDMETHODCALLTYPE
324ShimRemoteDataTarget::ContinueStatusChanged(
325 DWORD dwThreadId,
326 CORDB_CONTINUE_STATUS dwContinueStatus)
327{
328 ReturnFailureIfStateNotOk();
329
330 _ASSERTE(!"ShimRemoteDataTarget::ContinueStatusChanged() is called unexpectedly");
331 if (m_fpContinueStatusChanged != NULL)
332 {
333 return m_fpContinueStatusChanged(m_pContinueStatusChangedUserData, dwThreadId, dwContinueStatus);
334 }
335 return E_NOTIMPL;
336}
337
338//---------------------------------------------------------------------------------------
339//
340// Unwind the stack to the next frame.
341//
342// Return Value:
343// context filled in with the next frame
344//
345HRESULT STDMETHODCALLTYPE
346ShimRemoteDataTarget::VirtualUnwind(DWORD threadId, ULONG32 contextSize, PBYTE context)
347{
348 return m_pTransport->VirtualUnwind(threadId, contextSize, context);
349}
350