Merge pull request #1174 from mikem8361/palinit
[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_hr = CORDBG_E_OBJECT_NEUTERED;
134 }
135
136 //---------------------------------------------------------------------------------------
137 //
138 // Construction method for data-target
139 //
140 // Arguments:
141 //      machineInfo  - (input) the IP address of the remote machine and the port number of the debugger proxy
142 //      processId    - (input) live OS process ID to build a data-target for.
143 //      ppDataTarget - (output) new data-target instance. This gets addreffed.
144 //
145 // Return Value:
146 //    S_OK on success.
147 //
148 // Assumptions:
149 //    pid is for a process on the remote machine specified by the IP address in machineInfo
150 //    Caller must release *ppDataTarget.
151 //
152
153 HRESULT BuildPlatformSpecificDataTarget(MachineInfo machineInfo,
154                                         DWORD processId, 
155                                         ShimDataTarget ** ppDataTarget)
156 {
157     HandleHolder hDummy;
158     HRESULT hr = E_FAIL;
159
160     ShimRemoteDataTarget * pRemoteDataTarget = NULL;
161     DbgTransportTarget *   pProxy = g_pDbgTransportTarget;
162     DbgTransportSession *  pTransport = NULL;
163
164     hr = pProxy->GetTransportForProcess(processId, &pTransport, &hDummy);
165     if (FAILED(hr))
166     {
167         goto Label_Exit;
168     }
169
170     if (!pTransport->WaitForSessionToOpen(10000))
171     {
172         hr = CORDBG_E_TIMEOUT;
173         goto Label_Exit;
174     }
175
176     pRemoteDataTarget = new (nothrow) ShimRemoteDataTarget(processId, pProxy, pTransport);
177     if (pRemoteDataTarget == NULL)
178     {
179         hr = E_OUTOFMEMORY;
180         goto Label_Exit;
181     }
182
183     _ASSERTE(SUCCEEDED(hr));
184     *ppDataTarget = pRemoteDataTarget;
185     pRemoteDataTarget->AddRef(); // must addref out-parameters
186
187 Label_Exit:
188     if (FAILED(hr))
189     {
190         if (pRemoteDataTarget != NULL)
191         {
192             // The ShimRemoteDataTarget has ownership of the proxy and the transport, 
193             // so we don't need to clean them up here.
194             delete pRemoteDataTarget;
195         }
196         else
197         {
198             if (pTransport != NULL)
199             {
200                 pProxy->ReleaseTransport(pTransport);
201             }
202         }
203     }
204
205     return hr;
206 }
207
208 // impl of interface method ICorDebugDataTarget::GetPlatform
209 HRESULT STDMETHODCALLTYPE
210 ShimRemoteDataTarget::GetPlatform( 
211         CorDebugPlatform *pPlatform)
212 {
213 #ifdef FEATURE_PAL
214      #if defined(DBG_TARGET_X86)
215          *pPlatform = CORDB_PLATFORM_POSIX_X86;
216      #elif defined(DBG_TARGET_AMD64)
217          *pPlatform = CORDB_PLATFORM_POSIX_AMD64;
218      #else
219          #error Unknown Processor.
220      #endif
221 #else
222     #if defined(DBG_TARGET_X86)
223         *pPlatform = CORDB_PLATFORM_WINDOWS_X86;
224     #elif defined(DBG_TARGET_AMD64)
225         *pPlatform = CORDB_PLATFORM_WINDOWS_AMD64;
226     #elif defined(DBG_TARGET_ARM)
227         *pPlatform = CORDB_PLATFORM_WINDOWS_ARM;
228     #elif defined(DBG_TARGET_ARM64)
229         *pPlatform = CORDB_PLATFORM_WINDOWS_ARM64;
230     #else
231         #error Unknown Processor.
232     #endif
233 #endif
234
235     return S_OK;
236 }
237
238 // impl of interface method ICorDebugDataTarget::ReadVirtual
239 HRESULT STDMETHODCALLTYPE
240 ShimRemoteDataTarget::ReadVirtual( 
241     CORDB_ADDRESS address,
242     PBYTE pBuffer,
243     ULONG32 cbRequestSize,
244     ULONG32 *pcbRead)
245 {
246     ReturnFailureIfStateNotOk();
247
248     HRESULT hr = E_FAIL;
249     hr = m_pTransport->ReadMemory(reinterpret_cast<BYTE *>(CORDB_ADDRESS_TO_PTR(address)), 
250                                   pBuffer, 
251                                   cbRequestSize);
252     if (pcbRead != NULL)
253     {
254         *pcbRead = (SUCCEEDED(hr) ? cbRequestSize : 0);
255     }
256     return hr;
257 }
258
259 // impl of interface method ICorDebugMutableDataTarget::WriteVirtual
260 HRESULT STDMETHODCALLTYPE
261 ShimRemoteDataTarget::WriteVirtual( 
262     CORDB_ADDRESS pAddress,
263     const BYTE * pBuffer,
264     ULONG32 cbRequestSize)
265 {
266     ReturnFailureIfStateNotOk();
267
268     HRESULT hr = E_FAIL;
269     hr = m_pTransport->WriteMemory(reinterpret_cast<BYTE *>(CORDB_ADDRESS_TO_PTR(pAddress)), 
270                                    const_cast<BYTE *>(pBuffer), 
271                                    cbRequestSize);
272     return hr;
273 }
274
275 // impl of interface method ICorDebugMutableDataTarget::GetThreadContext
276 HRESULT STDMETHODCALLTYPE
277 ShimRemoteDataTarget::GetThreadContext(
278     DWORD dwThreadID,
279     ULONG32 contextFlags,
280     ULONG32 contextSize,
281     BYTE * pContext)
282 {
283     ReturnFailureIfStateNotOk();
284         
285 #ifdef FEATURE_DBGIPC_TRANSPORT_DI
286     // GetThreadContext() is currently not implemented in ShimRemoteDataTarget, which is used with our pipe transport 
287     // (FEATURE_DBGIPC_TRANSPORT_DI). Pipe transport is used on POSIX system, but occasionally we can turn it on for Windows for testing,
288     // and then we'd like to have same behavior as on POSIX system (zero context).
289     //
290     // 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 
291     // thread handle.  The function to do the conversion is OpenThread(), which is not implemented in PAL. Even if we had a handle, PAL implementation 
292     // of GetThreadContext() is very limited and doesn't work when we're not attached with ptrace. 
293     // Instead, we just zero out the seed CONTEXT for the stackwalk.  This tells the stackwalker to
294     // start the stackwalk with the first explicit frame.  This won't work when we do native debugging, 
295     // but that won't happen on the POSIX systems since they don't support native debugging.
296     ZeroMemory(pContext, contextSize);        
297     return S_OK;
298 #else
299     // ICorDebugDataTarget::GetThreadContext() and ICorDebugDataTarget::SetThreadContext() are currently only 
300     // required for interop-debugging and inspection of floating point registers, both of which are not 
301     // implemented on Mac.
302     _ASSERTE(!"The remote data target doesn't know how to get a thread's CONTEXT.");
303     return E_NOTIMPL;
304 #endif  // DFEATURE_DBGIPC_TRANSPORT_DI
305 }
306
307 // impl of interface method ICorDebugMutableDataTarget::SetThreadContext
308 HRESULT STDMETHODCALLTYPE
309 ShimRemoteDataTarget::SetThreadContext(
310     DWORD dwThreadID,
311     ULONG32 contextSize,
312     const BYTE * pContext)
313 {
314     ReturnFailureIfStateNotOk();
315
316     // ICorDebugDataTarget::GetThreadContext() and ICorDebugDataTarget::SetThreadContext() are currently only 
317     // required for interop-debugging and inspection of floating point registers, both of which are not 
318     // implemented on Mac.
319     _ASSERTE(!"The remote data target doesn't know how to set a thread's CONTEXT.");
320     return E_NOTIMPL;
321 }
322
323 // Public implementation of ICorDebugMutableDataTarget::ContinueStatusChanged
324 HRESULT STDMETHODCALLTYPE
325 ShimRemoteDataTarget::ContinueStatusChanged(
326     DWORD dwThreadId,
327     CORDB_CONTINUE_STATUS dwContinueStatus)
328 {
329     ReturnFailureIfStateNotOk();
330
331     _ASSERTE(!"ShimRemoteDataTarget::ContinueStatusChanged() is called unexpectedly");
332     if (m_fpContinueStatusChanged != NULL)
333     {
334         return m_fpContinueStatusChanged(m_pContinueStatusChangedUserData, dwThreadId, dwContinueStatus);
335     }
336     return E_NOTIMPL;
337 }