Enable build with clang 4.0 (#11226)
[platform/upstream/coreclr.git] / src / debug / di / windowspipeline.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 // File: WindowsPipeline.cpp
6 // 
7
8 //
9 // Implements the native-pipeline on Windows OS.
10 //*****************************************************************************
11
12 #include "stdafx.h"
13 #include "nativepipeline.h"
14
15 #include <Tlhelp32.h>
16
17 #include "holder.h"
18
19
20 DWORD GetProcessId(const DEBUG_EVENT * pEvent)
21 {
22     return pEvent->dwProcessId;
23 }
24 DWORD GetThreadId(const DEBUG_EVENT * pEvent)
25 {
26     return pEvent->dwThreadId;
27 }
28
29 // Get exception event
30 BOOL IsExceptionEvent(const DEBUG_EVENT * pEvent, BOOL * pfFirstChance, const EXCEPTION_RECORD ** ppRecord)
31 {
32     if (pEvent->dwDebugEventCode != EXCEPTION_DEBUG_EVENT)
33     {
34         *pfFirstChance = FALSE;
35         *ppRecord = NULL;
36         return FALSE;
37     }
38     *pfFirstChance = pEvent->u.Exception.dwFirstChance;
39     *ppRecord = &(pEvent->u.Exception.ExceptionRecord);
40     return TRUE;
41 }
42
43
44 //---------------------------------------------------------------------------------------
45 // Class serves as a connector to win32 native-debugging API.
46 class WindowsNativePipeline : 
47     public INativeEventPipeline
48 {
49 public:
50     WindowsNativePipeline()
51     {
52         // Default value for Win32.
53         m_fKillOnExit = true;
54         m_dwProcessId = 0;
55     }
56
57     // Call to free up the pipeline.
58     virtual void Delete();
59
60     virtual BOOL DebugSetProcessKillOnExit(bool fKillOnExit);
61
62     // Create
63     virtual HRESULT CreateProcessUnderDebugger(
64         MachineInfo machineInfo,
65         LPCWSTR lpApplicationName,
66         LPCWSTR lpCommandLine,
67         LPSECURITY_ATTRIBUTES lpProcessAttributes,
68         LPSECURITY_ATTRIBUTES lpThreadAttributes,
69         BOOL bInheritHandles,
70         DWORD dwCreationFlags,
71         LPVOID lpEnvironment,
72         LPCWSTR lpCurrentDirectory,
73         LPSTARTUPINFOW lpStartupInfo,
74         LPPROCESS_INFORMATION lpProcessInformation);
75
76     // Attach
77     virtual HRESULT DebugActiveProcess(MachineInfo machineInfo, DWORD processId);
78
79     // Detach
80     virtual HRESULT DebugActiveProcessStop(DWORD processId);
81
82     virtual BOOL WaitForDebugEvent(DEBUG_EVENT * pEvent, DWORD dwTimeout, CordbProcess * pProcess);
83
84     virtual BOOL ContinueDebugEvent(
85       DWORD dwProcessId,
86       DWORD dwThreadId,
87       DWORD dwContinueStatus
88     );
89
90     // Return a handle for the debuggee process.
91     virtual HANDLE GetProcessHandle();
92
93     // Terminate the debuggee process.
94     virtual BOOL TerminateProcess(UINT32 exitCode);
95
96     // Resume any suspended threads
97     virtual HRESULT EnsureThreadsRunning();
98
99 protected:
100     void UpdateDebugSetProcessKillOnExit();
101
102     HRESULT IsRemoteDebuggerPresent(DWORD processId, BOOL* pfDebuggerPresent);
103
104     // Cached value from DebugSetProcessKillOnExit.
105     // This is thread-local, and impacts all debuggees on the thread.
106     bool m_fKillOnExit;
107
108     DWORD m_dwProcessId;
109 };
110
111 // Allocate and return a pipeline object for this platform
112 INativeEventPipeline * NewPipelineForThisPlatform()
113 {
114     return new (nothrow) WindowsNativePipeline();
115 }
116
117 // Call to free up the pipeline.
118 void WindowsNativePipeline::Delete()
119 {
120     delete this;
121 }
122
123
124 // set whether to kill outstanding debuggees when the debugger exits.
125 BOOL WindowsNativePipeline::DebugSetProcessKillOnExit(bool fKillOnExit)
126 {
127     // Can't call kernel32!DebugSetProcessKillOnExit until after the event thread
128     // has spawned a debuggee. So cache the value now and call it later.
129     // This bit is enforced in code:WindowsNativePipeline::UpdateDebugSetProcessKillOnExit
130     m_fKillOnExit = fKillOnExit;
131     return TRUE;
132 }
133
134 // Enforces the bit set in code:WindowsNativePipeline::DebugSetProcessKillOnExit
135 void WindowsNativePipeline::UpdateDebugSetProcessKillOnExit()
136 {
137 #if !defined(FEATURE_CORESYSTEM)
138     // Late bind to DebugSetProcessKillOnExit - WinXP and above only
139     HModuleHolder hKernel32;
140     hKernel32 = WszLoadLibrary(W("kernel32"));
141     SIMPLIFYING_ASSUMPTION(hKernel32 != NULL);
142     if (hKernel32 == NULL)
143         return;
144
145     typedef BOOL (*DebugSetProcessKillOnExitSig) (BOOL);
146     DebugSetProcessKillOnExitSig pDebugSetProcessKillOnExit = 
147         reinterpret_cast<DebugSetProcessKillOnExitSig>(GetProcAddress(hKernel32, "DebugSetProcessKillOnExit"));
148
149     // If the API doesn't exist (eg. Win2k) - there isn't anything we can do, just
150     // silently ignore the request.
151     if (pDebugSetProcessKillOnExit == NULL)
152         return;
153
154     BOOL ret = pDebugSetProcessKillOnExit(m_fKillOnExit);
155
156     // Not a good failure path here. 
157     // 1) This shouldn't fail.
158     // 2) Even if it does, this is likely called after the debuggee
159     // has already been created, and if this API fails, most scenarios will
160     // be unaffected, so we don't want to fail the overall debugging session. 
161     SIMPLIFYING_ASSUMPTION(ret);
162
163 #else
164         // The API doesn't exit on CoreSystem, just return
165         return;
166 #endif
167 }
168
169 // Create an process under the debugger.
170 HRESULT WindowsNativePipeline::CreateProcessUnderDebugger(
171     MachineInfo machineInfo,
172     LPCWSTR lpApplicationName,
173     LPCWSTR lpCommandLine,
174     LPSECURITY_ATTRIBUTES lpProcessAttributes,
175     LPSECURITY_ATTRIBUTES lpThreadAttributes,
176     BOOL bInheritHandles,
177     DWORD dwCreationFlags,
178     LPVOID lpEnvironment,
179     LPCWSTR lpCurrentDirectory,
180     LPSTARTUPINFOW lpStartupInfo,
181     LPPROCESS_INFORMATION lpProcessInformation)
182 {
183     // This is always doing Native-debugging at the OS-level.
184     dwCreationFlags |= (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS);
185
186     BOOL ret = ::WszCreateProcess(
187           lpApplicationName,
188           lpCommandLine,
189           lpProcessAttributes,
190           lpThreadAttributes,
191           bInheritHandles,
192           dwCreationFlags,
193           lpEnvironment,
194           lpCurrentDirectory,
195           lpStartupInfo,
196           lpProcessInformation);
197     if (!ret)
198     {
199         return HRESULT_FROM_GetLastError();
200     }
201
202     m_dwProcessId = lpProcessInformation->dwProcessId;
203     UpdateDebugSetProcessKillOnExit();
204     return S_OK;    
205 }
206
207 // Attach the debugger to this process.
208 HRESULT WindowsNativePipeline::DebugActiveProcess(MachineInfo machineInfo, DWORD processId)
209 {
210     HRESULT hr = E_FAIL;
211     BOOL ret = ::DebugActiveProcess(processId);
212
213     if (ret)
214     {
215         hr = S_OK;
216         m_dwProcessId = processId;
217         UpdateDebugSetProcessKillOnExit();
218     }
219     else
220     {
221         hr = HRESULT_FROM_GetLastError();
222
223         // There are at least two scenarios in which DebugActiveProcess() returns E_INVALIDARG: 
224         //     1) if the specified process doesn't exist, or
225         //     2) if the specified process already has a debugger atttached
226         // We need to distinguish these two cases in order to return the correct HR.
227         if (hr == E_INVALIDARG)
228         {
229             // Check whether a debugger is known to be already attached.
230             // Note that this API won't work on some OSes, in which case we err on the side of returning E_INVALIDARG
231             // even though a debugger may be attached.  Another approach could be to assume that if
232             // OpenProcess succeeded, then DebugActiveProcess must only have failed because a debugger is
233             // attached.  But I think it's better to only return the specific error code if we know for sure
234             // the case is true.
235             BOOL fIsDebuggerPresent = FALSE;
236             if (SUCCEEDED(IsRemoteDebuggerPresent(processId, &fIsDebuggerPresent)))
237             {
238                 if (fIsDebuggerPresent)
239                 {
240                     hr = CORDBG_E_DEBUGGER_ALREADY_ATTACHED;
241                 }
242             }
243         }
244     }
245
246     return hr;
247 }
248
249 // Determine (if possible) whether a debugger is attached to the target process
250 HRESULT WindowsNativePipeline::IsRemoteDebuggerPresent(DWORD processId, BOOL* pfDebuggerPresent)
251 {
252 #if !defined(FEATURE_CORESYSTEM)
253
254     // Get a process handle for the process ID.
255     HandleHolder hProc = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, processId);
256     if (hProc == NULL)
257         return HRESULT_FROM_GetLastError();
258
259     // Delay-bind to CheckRemoteDebuggerPresent - WinXP SP1 and above only
260     HModuleHolder hKernel32;
261     hKernel32 = WszLoadLibrary(W("kernel32"));
262     if (hKernel32 == NULL)
263         return HRESULT_FROM_GetLastError();
264
265     typedef BOOL (*CheckRemoteDebuggerPresentSig) (HANDLE, PBOOL);
266     CheckRemoteDebuggerPresentSig pCheckRemoteDebuggerPresent = 
267         reinterpret_cast<CheckRemoteDebuggerPresentSig>(GetProcAddress(hKernel32, "CheckRemoteDebuggerPresent"));
268     if (pCheckRemoteDebuggerPresent == NULL)
269         return HRESULT_FROM_GetLastError();
270
271     // API exists - call it
272     if (!pCheckRemoteDebuggerPresent(hProc, pfDebuggerPresent))
273         return HRESULT_FROM_GetLastError();
274
275     return S_OK;
276 #else
277
278         //CoreSystem doesn't have this API
279         return E_FAIL;
280 #endif
281 }
282
283 // Detach
284 HRESULT WindowsNativePipeline::DebugActiveProcessStop(DWORD processId)
285 {
286 #if !defined(FEATURE_CORESYSTEM)
287     // Late-bind to DebugActiveProcessStop since it's WinXP and above only
288     HModuleHolder hKernel32;
289     hKernel32 = WszLoadLibrary(W("kernel32"));
290     if (hKernel32 == NULL)
291         return HRESULT_FROM_GetLastError();
292
293     typedef BOOL (*DebugActiveProcessStopSig) (DWORD);
294     DebugActiveProcessStopSig pDebugActiveProcessStop = 
295         reinterpret_cast<DebugActiveProcessStopSig>(GetProcAddress(hKernel32, "DebugActiveProcessStop"));
296
297     // Win2K will fail here - can't find DebugActiveProcessStop
298     if (pDebugActiveProcessStop == NULL)
299         return HRESULT_FROM_GetLastError();
300
301     // Ok, the API exists, call it
302     if (!pDebugActiveProcessStop(processId))
303     {
304         // Detach itself failed
305         return HRESULT_FROM_GetLastError();
306     }
307 #else
308         // The API exists, call it
309     if (!::DebugActiveProcessStop(processId))
310     {
311         // Detach itself failed
312         return HRESULT_FROM_GetLastError();
313     }
314 #endif
315     return S_OK;
316 }
317
318 BOOL WindowsNativePipeline::WaitForDebugEvent(DEBUG_EVENT * pEvent, DWORD dwTimeout, CordbProcess * pProcess)
319 {
320     return ::WaitForDebugEvent(pEvent, dwTimeout);
321 }
322
323 BOOL WindowsNativePipeline::ContinueDebugEvent(
324   DWORD dwProcessId,
325   DWORD dwThreadId,
326   DWORD dwContinueStatus
327 )
328 {
329     return ::ContinueDebugEvent(dwProcessId, dwThreadId, dwContinueStatus);
330 }
331
332 // Return a handle for the debuggee process.
333 HANDLE WindowsNativePipeline::GetProcessHandle()
334 {
335     _ASSERTE(m_dwProcessId != 0);
336
337     return ::OpenProcess(PROCESS_DUP_HANDLE        |
338                          PROCESS_QUERY_INFORMATION |
339                          PROCESS_TERMINATE         |
340                          PROCESS_VM_OPERATION      |
341                          PROCESS_VM_READ           |
342                          PROCESS_VM_WRITE          |
343                          SYNCHRONIZE,
344                          FALSE,
345                          m_dwProcessId);
346 }
347
348 // Terminate the debuggee process.
349 BOOL WindowsNativePipeline::TerminateProcess(UINT32 exitCode)
350 {
351     _ASSERTE(m_dwProcessId != 0);
352
353     // Get a process handle for the process ID.
354     HandleHolder hProc = OpenProcess(PROCESS_TERMINATE, FALSE, m_dwProcessId);
355
356     if (hProc == NULL)
357     {
358         return FALSE;
359     }
360
361     return ::TerminateProcess(hProc, exitCode);
362 }
363
364 // Resume any suspended threads (but just once)
365 HRESULT WindowsNativePipeline::EnsureThreadsRunning()
366 {
367 #ifdef FEATURE_CORESYSTEM
368         _ASSERTE("NYI");
369         return E_FAIL;
370 #else
371     _ASSERTE(m_dwProcessId != 0);
372
373     // Take a snapshot of all running threads (similar to ShimProcess::QueueFakeThreadAttachEventsNativeOrder)
374     // Alternately we could return thread creation/exit in WaitForDebugEvent.  But we expect this to be used 
375     // very rarely, so no need to complicate more common codepaths.
376     HANDLE hThreadSnap = INVALID_HANDLE_VALUE; 
377     THREADENTRY32 te32; 
378
379     hThreadSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); 
380     if (hThreadSnap == INVALID_HANDLE_VALUE) 
381         return HRESULT_FROM_GetLastError();
382
383     // HandleHolder doesn't deal with INVALID_HANDLE_VALUE, so we only assign if we have a legal value.
384     HandleHolder hSnapshotHolder(hThreadSnap);
385
386     // Fill in the size of the structure before using it. 
387     te32.dwSize = sizeof(THREADENTRY32); 
388
389     // Retrieve information about the first thread, and exit if unsuccessful
390     if (!Thread32First(hThreadSnap, &te32)) 
391         return HRESULT_FROM_GetLastError();
392
393     // Now walk the thread list of the system and attempt to resume any that are part of this process
394     // Ignore errors - this is a best effort (but ASSERT in CHK builds since we don't expect errors
395     // in practice - we expect the process to be frozen at a debug event, so no races etc.)
396
397     HRESULT hr = S_FALSE;   // no thread was resumed
398     do 
399     { 
400         if (te32.th32OwnerProcessID == m_dwProcessId)
401         {
402             HandleHolder hThread = ::OpenThread(THREAD_SUSPEND_RESUME, FALSE, te32.th32ThreadID);
403             _ASSERTE(hThread != NULL);
404             if (hThread != NULL)
405             {
406                 // Resume each thread exactly once (if they were suspended multiple times, 
407                 // then EnsureThreadsRunning would need to be called multiple times until it
408                 // returned S_FALSE.
409                 DWORD prevCount = ::ResumeThread(hThread);
410                 _ASSERTE(prevCount >= 0);
411                 if (prevCount >= 1)
412                     hr = S_OK;      // some thread was resumed
413             }
414         }
415     } while(Thread32Next(hThreadSnap, &te32)); 
416
417     return hr;
418 #endif
419 }