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// NativePipeline.h
6//
7
8//
9// defines native pipeline abstraction, which includes debug-support
10// for event redirection.
11//*****************************************************************************
12
13
14#ifndef _NATIVE_PIPELINE_H
15#define _NATIVE_PIPELINE_H
16
17//-----------------------------------------------------------------------------
18// Interface for native-debugging pipeline associated with a single process
19// that is being debugged.
20//
21// On windows, this is a wrapper around the win32 debugging API
22// (eg, kernel32!WaitForDebugEvent). On most Unix-like platforms,
23// it has an alternative implementation. See code:IEventChannel and
24// platformspecific.cpp for more information.
25// @dbgtodo : All of the APIs that return BOOL should probably be changed to
26// return HRESULTS so we don't have to rely on some implicit GetLastError protocol.
27//-----------------------------------------------------------------------------
28class INativeEventPipeline
29{
30public:
31 // Call to delete the pipeline. This can only be called once.
32 virtual void Delete() = 0;
33
34
35 //
36 // set whether to kill outstanding debuggees when the debugger exits.
37 //
38 // Arguments:
39 // fKillOnExit - When the debugger thread (this thread) exits, outstanding debuggees will be
40 // terminated (if true), else detached (if false)
41 //
42 // Returns:
43 // True on success, False on failure.
44 //
45 // Notes:
46 // This is a cross-platform wrapper around Kernel32!DebugSetProcessKillOnExit.
47 // This affects all debuggees handled by this thread.
48 // This is not supported or necessary for Mac debugging. The only reason we need this on Windows is to
49 // ask the OS not to terminate the debuggee when the debugger exits. The Mac debugging pipeline
50 // doesn't automatically kill the debuggee when the debugger exits.
51 //
52
53 virtual BOOL DebugSetProcessKillOnExit(bool fKillOnExit) = 0;
54
55 // Create
56 virtual HRESULT CreateProcessUnderDebugger(
57 MachineInfo machineInfo,
58 LPCWSTR lpApplicationName,
59 LPCWSTR lpCommandLine,
60 LPSECURITY_ATTRIBUTES lpProcessAttributes,
61 LPSECURITY_ATTRIBUTES lpThreadAttributes,
62 BOOL bInheritHandles,
63 DWORD dwCreationFlags,
64 LPVOID lpEnvironment,
65 LPCWSTR lpCurrentDirectory,
66 LPSTARTUPINFOW lpStartupInfo,
67 LPPROCESS_INFORMATION lpProcessInformation) = 0;
68
69 // Attach
70 virtual HRESULT DebugActiveProcess(MachineInfo machineInfo, const ProcessDescriptor& processDescriptor) = 0;
71
72 // Detach
73 virtual HRESULT DebugActiveProcessStop(DWORD processId) =0;
74
75 //
76 // Block and wait for the next debug event from the debuggee process.
77 //
78 // Arguments:
79 // pEvent - buffer for the debug event to be returned
80 // dwTimeout - number of milliseconds to wait before timing out
81 // pProcess - the CordbProcess associated with this pipeline; used to look up a thread ID if necessary
82 //
83 // Return Value:
84 // TRUE if a debug event is available
85 //
86 // Notes:
87 // Once a debug event is returned, it is consumed from the pipeline and will not be accessible in the
88 // future. Caller is responsible for saving the debug event if necessary.
89 //
90
91 virtual BOOL WaitForDebugEvent(DEBUG_EVENT * pEvent, DWORD dwTimeout, CordbProcess * pProcess) =0;
92
93 //
94 // This is specific to Windows. When a debug event is sent to the debugger, the debuggee process is
95 // suspended. The debugger must call this function to resume the debuggee process.
96 //
97 // Arguments:
98 // dwProcessId - process ID of the debuggee
99 // dwThreadId - thread ID of the thread which has triggered a debug event before
100 // dwContinueStatus - whether to handle the exception (if any) reported on the specified thread
101 //
102 // Return Value:
103 // TRUE if successful
104 //
105 // Notes:
106 // For Mac debugging, the process isn't actually suspended when a debug event is raised. As such,
107 // this function is a nop for Mac debugging. See code:Debugger::SendRawEvent.
108 //
109 // Of course, this is a semantic difference from Windows. However, in most cases, the LS suspends
110 // all managed threads by calling code:Debugger::TrapAllRuntimeThreads immediately after raising a
111 // debug event. The only case where this is not true is code:Debugger::SendCreateProcess, but that
112 // doesn't seem to be a problem at this point.
113 //
114
115 virtual BOOL ContinueDebugEvent(
116 DWORD dwProcessId,
117 DWORD dwThreadId,
118 DWORD dwContinueStatus
119 ) =0;
120
121 //
122 // Return a handle for the debuggee process.
123 //
124 // Return Value:
125 // handle for the debuggee process (see below)
126 //
127 // Notes:
128 // Handles are a Windows-specific concept. For Mac debugging, the handle returned by this function is
129 // only valid for waiting on process termination. This is ok for now because the only cases where a
130 // real process handle is needed are related to interop-debugging, which isn't supported on the Mac.
131 //
132
133 virtual HANDLE GetProcessHandle() = 0;
134
135 //
136 // Terminate the debuggee process.
137 //
138 // Arguments:
139 // exitCode - the exit code for the debuggee process
140 //
141 // Return Value:
142 // TRUE if successful
143 //
144 // Notes:
145 // The exit code is ignored for Mac debugging.
146 //
147
148 virtual BOOL TerminateProcess(UINT32 exitCode) = 0;
149
150 //
151 // Resume any suspended threads in the currend process.
152 // This decreases the suspend count of each thread by at most 1.
153 // Call multiple times until it returns S_FALSE if you want to really ensure
154 // all threads are running.
155 //
156 // Notes:
157 // On Windows the OS may suspend threads when continuing a 2nd-chance exception.
158 // Call this to get them resumed again. On other platforms this
159 // will typically be a no-op, so I provide a default implementation to avoid
160 // everyone having to override this.
161 //
162 // Return Value:
163 // S_OK if at least one thread was resumed from a suspended state
164 // S_FALSE if nothing was done
165 // An error code indicating why we were not able to attempt this
166
167 virtual HRESULT EnsureThreadsRunning()
168 {
169 return S_FALSE;
170 }
171
172#ifdef FEATURE_PAL
173 // Used by debugger side (RS) to cleanup the target (LS) named pipes
174 // and semaphores when the debugger detects the debuggee process exited.
175 virtual void CleanupTargetProcess()
176 {
177 }
178#endif
179};
180
181//
182// Helper accessors for manipulating native pipeline.
183// These also provide some platform abstractions for DEBUG_EVENT.
184//
185
186// Returns process ID that the debug event is on.
187DWORD GetProcessId(const DEBUG_EVENT * pEvent);
188
189// Returns Thread ID of the thread that fired the debug event.
190DWORD GetThreadId(const DEBUG_EVENT * pEvent);
191
192//
193// Determines if this is an exception event.
194//
195// Arguments:
196// pEvent - [required, in]: debug event to inspect
197// pfFirstChance - [required, out]: set if this is an 1st-chance exception.
198// ppRecord - [required, out]: if this is an exception, pointer into to the exception record.
199// this pointer has the same lifetime semantics as the DEBUG_EVENT (it may
200// likely be a pointer into the debug-event).
201//
202// Returns:
203// True if this is an exception. Sets outparameters to exception values.
204// Else false.
205//
206// Notes:
207// Exceptions are spceial because they need to be sent to the CLR for filtering.
208BOOL IsExceptionEvent(const DEBUG_EVENT * pEvent, BOOL * pfFirstChance, const EXCEPTION_RECORD ** ppRecord);
209
210
211//-----------------------------------------------------------------------------
212// Allocate and return a pipeline object for this platform
213//
214// Returns:
215// newly allocated pipeline object. Caller must call Dispose() on it.
216INativeEventPipeline * NewPipelineForThisPlatform();
217
218//-----------------------------------------------------------------------------
219// Allocate and return a pipeline object for this platform
220// Has debug checks (such as for event redirection)
221//
222// Returns:
223// newly allocated pipeline object. Caller must call Dispose() on it.
224INativeEventPipeline * NewPipelineWithDebugChecks();
225
226
227
228#endif // _NATIVE_PIPELINE_H
229
230