Merge pull request #2893 from swaroop-sridhar/redirect
[platform/upstream/coreclr.git] / src / debug / di / dbgtransportmanager.cpp
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 #include "stdafx.h"
6 #include "dbgtransportsession.h"
7 #include "dbgtransportmanager.h"
8 #include "coreclrremotedebugginginterfaces.h"
9
10
11
12 #ifdef FEATURE_DBGIPC_TRANSPORT_DI
13
14 DbgTransportTarget *g_pDbgTransportTarget = NULL;
15
16 DbgTransportTarget::DbgTransportTarget()
17 {
18     memset(this, 0, sizeof(*this));
19 }
20
21 // Initialization routine called only by the DbgTransportManager.
22 HRESULT DbgTransportTarget::Init()
23 {
24     m_sLock.Init("DbgTransportTarget Lock", RSLock::cLockFlat, RSLock::LL_DBG_TRANSPORT_TARGET_LOCK);
25
26     return S_OK;
27 }
28
29 // Shutdown routine called only by the DbgTransportManager.
30 void DbgTransportTarget::Shutdown()
31 {
32     DbgTransportLog(LC_Always, "DbgTransportTarget shutting down");
33
34     {
35         RSLockHolder lock(&m_sLock);
36         while (m_pProcessList)
37         {
38             ProcessEntry *pDelProcess = m_pProcessList;
39             m_pProcessList = m_pProcessList->m_pNext;
40             delete pDelProcess;
41         }
42     }
43     m_sLock.Destroy();
44 }
45
46
47 // Given a PID attempt to find or create a DbgTransportSession instance to manage a connection to a runtime in
48 // that process. Returns E_UNEXPECTED if the process can't be found. Also returns a handle that can be waited
49 // on for process termination.
50 HRESULT DbgTransportTarget::GetTransportForProcess(DWORD                   dwPID,
51                                                    DbgTransportSession   **ppTransport,
52                                                    HANDLE                 *phProcessHandle)
53 {
54     RSLockHolder lock(&m_sLock);
55     HRESULT hr = S_OK;
56
57     ProcessEntry *entry = LocateProcessByPID(dwPID);
58
59     if (entry == NULL)
60     {
61
62        NewHolder<ProcessEntry> newEntry = new(nothrow) ProcessEntry();
63        if (newEntry == NULL)
64            return E_OUTOFMEMORY;
65
66        NewHolder<DbgTransportSession> transport = new(nothrow) DbgTransportSession();
67        if (transport == NULL)
68        {
69            return E_OUTOFMEMORY;
70        }
71
72
73        HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwPID);
74        if (hProcess == NULL)
75        {
76            transport->Shutdown();
77            return HRESULT_FROM_GetLastError();
78        }
79
80        // Initialize it (this immediately starts the remote connection process).
81        hr = transport->Init(dwPID, hProcess);
82        if (FAILED(hr))
83        {
84            transport->Shutdown();
85            CloseHandle(hProcess);
86            return hr;
87        }
88
89        entry = newEntry;
90        newEntry.SuppressRelease();   
91        entry->m_dwPID = dwPID;
92        entry->m_hProcess = hProcess;
93        entry->m_transport = transport;
94        transport.SuppressRelease();
95        entry->m_cProcessRef = 0;
96
97        // Adding new entry to the list.
98        entry->m_pNext = m_pProcessList;
99        m_pProcessList = entry;
100     }
101
102     entry->m_cProcessRef++;
103     _ASSERTE(entry->m_cProcessRef > 0);
104     _ASSERTE(entry->m_transport != NULL);
105     _ASSERTE(entry->m_hProcess > 0);
106     
107     *ppTransport = entry->m_transport;
108     if (!DuplicateHandle(GetCurrentProcess(), 
109                          entry->m_hProcess,
110                          GetCurrentProcess(), 
111                          phProcessHandle,
112                          0,      // ignored since we are going to pass DUPLICATE_SAME_ACCESS
113                          FALSE, 
114                          DUPLICATE_SAME_ACCESS))
115     {
116         return HRESULT_FROM_GetLastError();
117     }
118
119     return hr;
120 }
121
122
123 // Release another reference to the transport associated with dwPID. Once all references are gone (modulo the
124 // manager's own weak reference) clean up the transport and deallocate it.
125 void DbgTransportTarget::ReleaseTransport(DbgTransportSession *pTransport)
126 {
127     RSLockHolder lock(&m_sLock);
128
129     ProcessEntry *entry = m_pProcessList;
130
131     // Pointer to the pointer that points to *entry.
132     // It either points to m_pProcessList or m_pNext of some entry.
133     // It is used to fix the linked list after deletion of an entry.
134     ProcessEntry **prevPtr = &m_pProcessList; 
135
136     // Looking for ProcessEntry with a given transport
137     while (entry)
138     {
139
140         _ASSERTE(entry->m_cProcessRef > 0);
141         _ASSERTE(entry->m_transport != NULL);
142         _ASSERTE(entry->m_hProcess > 0);
143
144         if (entry->m_transport == pTransport)
145         {
146             // Mark that it has one less holder now
147             entry->m_cProcessRef--;
148
149             // If no more holders remove the entry from the list and free resources
150             if (entry->m_cProcessRef == 0)
151             {
152                 *prevPtr = entry->m_pNext;
153                 delete entry;
154             }
155             return;
156         }
157         prevPtr = &entry->m_pNext;
158         entry = entry->m_pNext;
159     }
160
161     _ASSERTE(!"Trying to release transport that doesn't belong to this DbgTransportTarget");
162     pTransport->Shutdown();
163 }
164
165 HRESULT DbgTransportTarget::CreateProcess(LPCWSTR lpApplicationName,
166                           LPCWSTR lpCommandLine,
167                           LPSECURITY_ATTRIBUTES lpProcessAttributes,
168                           LPSECURITY_ATTRIBUTES lpThreadAttributes,
169                           BOOL bInheritHandles,
170                           DWORD dwCreationFlags,
171                           LPVOID lpEnvironment,
172                           LPCWSTR lpCurrentDirectory,
173                           LPSTARTUPINFOW lpStartupInfo,
174                           LPPROCESS_INFORMATION lpProcessInformation)
175 {
176
177     BOOL result = WszCreateProcess(lpApplicationName, 
178                                    lpCommandLine,
179                                    lpProcessAttributes,
180                                    lpThreadAttributes,
181                                    bInheritHandles,
182                                    dwCreationFlags,
183                                    lpEnvironment,
184                                    lpCurrentDirectory,
185                                    lpStartupInfo,
186                                    lpProcessInformation);
187
188     if (!result) 
189     {
190         return HRESULT_FROM_GetLastError();
191     }
192
193     return S_OK;
194 }
195
196 // Kill the process identified by PID.
197 void DbgTransportTarget::KillProcess(DWORD dwPID)
198 {
199     HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, dwPID);
200     if (hProcess != NULL)
201     {
202         TerminateProcess(hProcess, 0);
203         CloseHandle(hProcess);
204     }
205 }
206
207 DbgTransportTarget::ProcessEntry::~ProcessEntry()
208 {
209     CloseHandle(m_hProcess);
210     m_hProcess = NULL;
211
212     m_transport->Shutdown();
213     m_transport = NULL;
214 }
215
216 // Locate a process entry by PID. Assumes the lock is already held.
217 DbgTransportTarget::ProcessEntry *DbgTransportTarget::LocateProcessByPID(DWORD dwPID)
218 {
219     _ASSERTE(m_sLock.HasLock());
220
221     ProcessEntry *pProcess = m_pProcessList;
222     while (pProcess)
223     {
224         if (pProcess->m_dwPID == dwPID)
225             return pProcess;
226         pProcess = pProcess->m_pNext;
227     }
228     return NULL;
229 }
230
231 #endif // FEATURE_DBGIPC_TRANSPORT_DI