| 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 |  | 
|---|