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 | //----------------------------------------------------------------------------- |
28 | class INativeEventPipeline |
29 | { |
30 | public: |
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. |
187 | DWORD GetProcessId(const DEBUG_EVENT * pEvent); |
188 | |
189 | // Returns Thread ID of the thread that fired the debug event. |
190 | DWORD 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. |
208 | BOOL 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. |
216 | INativeEventPipeline * 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. |
224 | INativeEventPipeline * NewPipelineWithDebugChecks(); |
225 | |
226 | |
227 | |
228 | #endif // _NATIVE_PIPELINE_H |
229 | |
230 | |