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