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