| 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 |  | 
|---|
| 6 | // | 
|---|
| 7 |  | 
|---|
| 8 | #ifndef __ExStateCommon_h__ | 
|---|
| 9 | #define __ExStateCommon_h__ | 
|---|
| 10 |  | 
|---|
| 11 | #include "stackframe.h" | 
|---|
| 12 |  | 
|---|
| 13 | class ExceptionFlags; | 
|---|
| 14 |  | 
|---|
| 15 | #ifdef DEBUGGING_SUPPORTED | 
|---|
| 16 | //--------------------------------------------------------------------------------------- | 
|---|
| 17 | // | 
|---|
| 18 | // This class stores information necessary to intercept an exception.  It's basically a communication channel | 
|---|
| 19 | // between the debugger and the EH subsystem.  Each internal exception tracking structure | 
|---|
| 20 | // (ExInfo on x86 and ExceptionTracker on WIN64) contains one DebuggerExState. | 
|---|
| 21 | // | 
|---|
| 22 | // Notes: | 
|---|
| 23 | //    This class actually stores more information on x86 than on WIN64 because the x86 EH subsystem | 
|---|
| 24 | //    has more work to do when unwinding the stack.  WIN64 just asks the OS to do it. | 
|---|
| 25 | // | 
|---|
| 26 |  | 
|---|
| 27 | class DebuggerExState | 
|---|
| 28 | { | 
|---|
| 29 | public: | 
|---|
| 30 |  | 
|---|
| 31 | //--------------------------------------------------------------------------------------- | 
|---|
| 32 | // | 
|---|
| 33 | // constructor | 
|---|
| 34 | // | 
|---|
| 35 |  | 
|---|
| 36 | DebuggerExState() | 
|---|
| 37 | { | 
|---|
| 38 | Init(); | 
|---|
| 39 | } | 
|---|
| 40 |  | 
|---|
| 41 | //--------------------------------------------------------------------------------------- | 
|---|
| 42 | // | 
|---|
| 43 | // This function is simply used to initialize all the fields in the DebuggerExState. | 
|---|
| 44 | // | 
|---|
| 45 |  | 
|---|
| 46 | void Init() | 
|---|
| 47 | { | 
|---|
| 48 | m_sfDebuggerIndicatedFramePointer = StackFrame(); | 
|---|
| 49 | m_pDebuggerInterceptFunc = NULL; | 
|---|
| 50 | m_sfDebuggerInterceptFramePointer = StackFrame(); | 
|---|
| 51 | m_pDebuggerContext = NULL; | 
|---|
| 52 | m_pDebuggerInterceptNativeOffset = 0; | 
|---|
| 53 |  | 
|---|
| 54 | #ifndef WIN64EXCEPTIONS | 
|---|
| 55 | // x86-specific fields | 
|---|
| 56 | m_pDebuggerInterceptFrame = EXCEPTION_CHAIN_END; | 
|---|
| 57 | #endif // !WIN64EXCEPTIONS | 
|---|
| 58 | m_dDebuggerInterceptHandlerDepth  = 0; | 
|---|
| 59 | } | 
|---|
| 60 |  | 
|---|
| 61 | //--------------------------------------------------------------------------------------- | 
|---|
| 62 | // | 
|---|
| 63 | // Retrieves the opaque token stored by the debugger. | 
|---|
| 64 | // | 
|---|
| 65 | // Return Value: | 
|---|
| 66 | //    the stored opaque token for the debugger | 
|---|
| 67 | // | 
|---|
| 68 |  | 
|---|
| 69 | void* GetDebuggerInterceptContext() | 
|---|
| 70 | { | 
|---|
| 71 | LIMITED_METHOD_CONTRACT; | 
|---|
| 72 | return m_pDebuggerContext; | 
|---|
| 73 | } | 
|---|
| 74 |  | 
|---|
| 75 | //--------------------------------------------------------------------------------------- | 
|---|
| 76 | // | 
|---|
| 77 | // Stores an opaque token which is only used by the debugger. | 
|---|
| 78 | // | 
|---|
| 79 | // Arguments: | 
|---|
| 80 | //    pContext - the token to be stored | 
|---|
| 81 | // | 
|---|
| 82 |  | 
|---|
| 83 | void SetDebuggerInterceptContext(void* pContext) | 
|---|
| 84 | { | 
|---|
| 85 | LIMITED_METHOD_CONTRACT; | 
|---|
| 86 | m_pDebuggerContext = pContext; | 
|---|
| 87 | } | 
|---|
| 88 |  | 
|---|
| 89 | //--------------------------------------------------------------------------------------- | 
|---|
| 90 | // | 
|---|
| 91 | // Marks the current stack frame visited by the EH subsystem during the first pass. | 
|---|
| 92 | // This marker moves closer to the root of the stack while each stack frame is examined in the first pass. | 
|---|
| 93 | // This continues until the end of the first pass. | 
|---|
| 94 | // | 
|---|
| 95 | // Arguments: | 
|---|
| 96 | //    stackPointer  - SP of the current stack frame | 
|---|
| 97 | //    bStorePointer - BSP of the current stack frame | 
|---|
| 98 | // | 
|---|
| 99 |  | 
|---|
| 100 | void SetDebuggerIndicatedFramePointer(void* stackPointer) | 
|---|
| 101 | { | 
|---|
| 102 | LIMITED_METHOD_CONTRACT; | 
|---|
| 103 | m_sfDebuggerIndicatedFramePointer = StackFrame((UINT_PTR)stackPointer); | 
|---|
| 104 | } | 
|---|
| 105 |  | 
|---|
| 106 | // This function stores the information necessary to intercept an exception in the DebuggerExState. | 
|---|
| 107 | BOOL SetDebuggerInterceptInfo(IJitManager *pJitManager, | 
|---|
| 108 | Thread *pThread, | 
|---|
| 109 | const METHODTOKEN& methodToken, | 
|---|
| 110 | MethodDesc *pMethDesc, | 
|---|
| 111 | ULONG_PTR natOffset, | 
|---|
| 112 | StackFrame sfDebuggerInterceptFramePointer, | 
|---|
| 113 | ExceptionFlags* pFlags); | 
|---|
| 114 |  | 
|---|
| 115 | //--------------------------------------------------------------------------------------- | 
|---|
| 116 | // | 
|---|
| 117 | // This function is basically just a getter to retrieve the information stored on the DebuggerExState. | 
|---|
| 118 | // Refer to the comments for individual fields for more information. | 
|---|
| 119 | // | 
|---|
| 120 | // Arguments: | 
|---|
| 121 | //    pEstablisherFrame - m_pDebuggerInterceptFrame | 
|---|
| 122 | //    ppFunc            - m_pDebuggerInterceptFunc | 
|---|
| 123 | //    pdHandler         - m_dDebuggerInterceptHandlerDepth | 
|---|
| 124 | //    ppStack           - the SP of m_sfDebuggerInterceptFramePointer | 
|---|
| 125 | //    ppBStore          - the BSP of m_sfDebuggerInterceptFramePointer | 
|---|
| 126 | //    pNativeOffset     - m_pDebuggerInterceptNativeOffset; | 
|---|
| 127 | //    ppFrame           - always set to NULL | 
|---|
| 128 | // | 
|---|
| 129 | // Notes: | 
|---|
| 130 | //    Everything is an out parameter. | 
|---|
| 131 | // | 
|---|
| 132 | //    Apparently ppFrame is actually used on x86 to set tct.pBottomFrame to NULL. | 
|---|
| 133 | // | 
|---|
| 134 |  | 
|---|
| 135 | void GetDebuggerInterceptInfo( | 
|---|
| 136 | #ifndef WIN64EXCEPTIONS | 
|---|
| 137 | PEXCEPTION_REGISTRATION_RECORD *pEstablisherFrame, | 
|---|
| 138 | #endif // !WIN64EXCEPTIONS | 
|---|
| 139 | MethodDesc **ppFunc, | 
|---|
| 140 | int *pdHandler, | 
|---|
| 141 | BYTE **ppStack, | 
|---|
| 142 | ULONG_PTR *pNativeOffset, | 
|---|
| 143 | Frame **ppFrame) | 
|---|
| 144 | { | 
|---|
| 145 | LIMITED_METHOD_CONTRACT; | 
|---|
| 146 |  | 
|---|
| 147 | #ifndef WIN64EXCEPTIONS | 
|---|
| 148 | if (pEstablisherFrame != NULL) | 
|---|
| 149 | { | 
|---|
| 150 | *pEstablisherFrame = m_pDebuggerInterceptFrame; | 
|---|
| 151 | } | 
|---|
| 152 | #endif // !WIN64EXCEPTIONS | 
|---|
| 153 |  | 
|---|
| 154 | if (ppFunc != NULL) | 
|---|
| 155 | { | 
|---|
| 156 | *ppFunc = m_pDebuggerInterceptFunc; | 
|---|
| 157 | } | 
|---|
| 158 |  | 
|---|
| 159 | if (pdHandler != NULL) | 
|---|
| 160 | { | 
|---|
| 161 | *pdHandler = m_dDebuggerInterceptHandlerDepth; | 
|---|
| 162 | } | 
|---|
| 163 |  | 
|---|
| 164 | if (ppStack != NULL) | 
|---|
| 165 | { | 
|---|
| 166 | *ppStack = (BYTE *)m_sfDebuggerInterceptFramePointer.SP; | 
|---|
| 167 | } | 
|---|
| 168 |  | 
|---|
| 169 | if (pNativeOffset != NULL) | 
|---|
| 170 | { | 
|---|
| 171 | *pNativeOffset = m_pDebuggerInterceptNativeOffset; | 
|---|
| 172 | } | 
|---|
| 173 |  | 
|---|
| 174 | if (ppFrame != NULL) | 
|---|
| 175 | { | 
|---|
| 176 | *ppFrame = NULL; | 
|---|
| 177 | } | 
|---|
| 178 | } | 
|---|
| 179 |  | 
|---|
| 180 | private: | 
|---|
| 181 | // This frame pointer marks the latest stack frame examined by the EH subsystem in the first pass. | 
|---|
| 182 | // An exception cannot be intercepted closer to the root than this frame pointer. | 
|---|
| 183 | StackFrame      m_sfDebuggerIndicatedFramePointer; | 
|---|
| 184 |  | 
|---|
| 185 | // the method in which we are going to resume execution | 
|---|
| 186 | MethodDesc*     m_pDebuggerInterceptFunc; | 
|---|
| 187 |  | 
|---|
| 188 | // the frame pointer of the stack frame where we are intercepting the exception | 
|---|
| 189 | StackFrame      m_sfDebuggerInterceptFramePointer; | 
|---|
| 190 |  | 
|---|
| 191 | // opaque token used by the debugger | 
|---|
| 192 | void*           m_pDebuggerContext; | 
|---|
| 193 |  | 
|---|
| 194 | // the native offset at which to resume execution | 
|---|
| 195 | ULONG_PTR       m_pDebuggerInterceptNativeOffset; | 
|---|
| 196 |  | 
|---|
| 197 | // The remaining fields are only used on x86. | 
|---|
| 198 | #ifndef WIN64EXCEPTIONS | 
|---|
| 199 | // the exception registration record covering the stack range containing the interception point | 
|---|
| 200 | PEXCEPTION_REGISTRATION_RECORD m_pDebuggerInterceptFrame; | 
|---|
| 201 | #endif // !WIN64EXCEPTIONS | 
|---|
| 202 |  | 
|---|
| 203 | // the nesting level at which we want to resume execution | 
|---|
| 204 | int             m_dDebuggerInterceptHandlerDepth; | 
|---|
| 205 | }; | 
|---|
| 206 | #endif // DEBUGGING_SUPPORTED | 
|---|
| 207 |  | 
|---|
| 208 | class EHClauseInfo | 
|---|
| 209 | { | 
|---|
| 210 | public: | 
|---|
| 211 | EHClauseInfo() | 
|---|
| 212 | { | 
|---|
| 213 | LIMITED_METHOD_CONTRACT; | 
|---|
| 214 |  | 
|---|
| 215 | // For the profiler, other clause fields are not valid if m_ClauseType is COR_PRF_CLAUSE_NONE. | 
|---|
| 216 | m_ClauseType           = COR_PRF_CLAUSE_NONE; | 
|---|
| 217 | m_IPForEHClause        = 0; | 
|---|
| 218 | m_sfForEHClause.Clear(); | 
|---|
| 219 | m_csfEHClause.Clear(); | 
|---|
| 220 | m_fManagedCodeEntered  = FALSE; | 
|---|
| 221 | } | 
|---|
| 222 |  | 
|---|
| 223 | void SetEHClauseType(COR_PRF_CLAUSE_TYPE EHClauseType) | 
|---|
| 224 | { | 
|---|
| 225 | LIMITED_METHOD_CONTRACT; | 
|---|
| 226 | m_ClauseType = EHClauseType; | 
|---|
| 227 | } | 
|---|
| 228 |  | 
|---|
| 229 | void SetInfo(COR_PRF_CLAUSE_TYPE EHClauseType, | 
|---|
| 230 | UINT_PTR            uIPForEHClause, | 
|---|
| 231 | StackFrame          sfForEHClause) | 
|---|
| 232 | { | 
|---|
| 233 | LIMITED_METHOD_CONTRACT; | 
|---|
| 234 |  | 
|---|
| 235 | m_ClauseType    = EHClauseType; | 
|---|
| 236 | m_IPForEHClause = uIPForEHClause; | 
|---|
| 237 | m_sfForEHClause = sfForEHClause; | 
|---|
| 238 | } | 
|---|
| 239 |  | 
|---|
| 240 | void ResetInfo() | 
|---|
| 241 | { | 
|---|
| 242 | LIMITED_METHOD_CONTRACT; | 
|---|
| 243 |  | 
|---|
| 244 | // For the profiler, other clause fields are not valid if m_ClauseType is COR_PRF_CLAUSE_NONE. | 
|---|
| 245 | m_ClauseType           = COR_PRF_CLAUSE_NONE; | 
|---|
| 246 | m_IPForEHClause        = 0; | 
|---|
| 247 | m_sfForEHClause.Clear(); | 
|---|
| 248 | m_csfEHClause.Clear(); | 
|---|
| 249 | } | 
|---|
| 250 |  | 
|---|
| 251 | void SetManagedCodeEntered(BOOL fEntered) | 
|---|
| 252 | { | 
|---|
| 253 | LIMITED_METHOD_CONTRACT; | 
|---|
| 254 | m_fManagedCodeEntered = fEntered; | 
|---|
| 255 | } | 
|---|
| 256 |  | 
|---|
| 257 | void SetCallerStackFrame(CallerStackFrame csfEHClause) | 
|---|
| 258 | { | 
|---|
| 259 | LIMITED_METHOD_CONTRACT; | 
|---|
| 260 | m_csfEHClause = csfEHClause; | 
|---|
| 261 | } | 
|---|
| 262 |  | 
|---|
| 263 | COR_PRF_CLAUSE_TYPE GetClauseType()     { LIMITED_METHOD_CONTRACT; return m_ClauseType;           } | 
|---|
| 264 |  | 
|---|
| 265 | UINT_PTR GetIPForEHClause()             { LIMITED_METHOD_CONTRACT; return m_IPForEHClause;        } | 
|---|
| 266 | UINT_PTR GetFramePointerForEHClause()   { LIMITED_METHOD_CONTRACT; return m_sfForEHClause.SP;     } | 
|---|
| 267 |  | 
|---|
| 268 | BOOL     IsManagedCodeEntered()         { LIMITED_METHOD_CONTRACT; return m_fManagedCodeEntered;  } | 
|---|
| 269 |  | 
|---|
| 270 | StackFrame GetStackFrameForEHClause()            { LIMITED_METHOD_CONTRACT; return m_sfForEHClause; } | 
|---|
| 271 | CallerStackFrame GetCallerStackFrameForEHClause(){ LIMITED_METHOD_CONTRACT; return m_csfEHClause;   } | 
|---|
| 272 |  | 
|---|
| 273 | // On some platforms, we make the call to the funclets via an assembly helper. The reference to the field | 
|---|
| 274 | // containing the stack pointer is passed to the assembly helper so that it can update | 
|---|
| 275 | // it with correct SP value once its prolog has executed. | 
|---|
| 276 | // | 
|---|
| 277 | // This method is used to get the field reference | 
|---|
| 278 | CallerStackFrame* GetCallerStackFrameForEHClauseReference() | 
|---|
| 279 | { | 
|---|
| 280 | LIMITED_METHOD_CONTRACT; | 
|---|
| 281 | return &m_csfEHClause; | 
|---|
| 282 | } | 
|---|
| 283 |  | 
|---|
| 284 | private: | 
|---|
| 285 | UINT_PTR         m_IPForEHClause;   // the entry point of the current notified exception clause | 
|---|
| 286 | StackFrame       m_sfForEHClause;   // the assocated frame pointer of the current notified exception clause | 
|---|
| 287 | CallerStackFrame m_csfEHClause;     // the caller SP of the funclet; only used on WIN64 | 
|---|
| 288 |  | 
|---|
| 289 | COR_PRF_CLAUSE_TYPE m_ClauseType;   // this has a value from COR_PRF_CLAUSE_TYPE while an exception notification is pending | 
|---|
| 290 | BOOL m_fManagedCodeEntered;         // this flag indicates that we have called the managed code for the current EH clause | 
|---|
| 291 | }; | 
|---|
| 292 |  | 
|---|
| 293 | class ExceptionFlags | 
|---|
| 294 | { | 
|---|
| 295 | public: | 
|---|
| 296 | ExceptionFlags() | 
|---|
| 297 | { | 
|---|
| 298 | Init(); | 
|---|
| 299 | } | 
|---|
| 300 |  | 
|---|
| 301 | #if defined(WIN64EXCEPTIONS) | 
|---|
| 302 | ExceptionFlags(bool fReadOnly) | 
|---|
| 303 | { | 
|---|
| 304 | Init(); | 
|---|
| 305 | #ifdef _DEBUG | 
|---|
| 306 | if (fReadOnly) | 
|---|
| 307 | { | 
|---|
| 308 | m_flags |= Ex_FlagsAreReadOnly; | 
|---|
| 309 | m_debugFlags |= Ex_FlagsAreReadOnly; | 
|---|
| 310 | } | 
|---|
| 311 | #endif // _DEBUG | 
|---|
| 312 | } | 
|---|
| 313 | #endif // defined(WIN64EXCEPTIONS) | 
|---|
| 314 |  | 
|---|
| 315 | void AssertIfReadOnly() | 
|---|
| 316 | { | 
|---|
| 317 | SUPPORTS_DAC; | 
|---|
| 318 |  | 
|---|
| 319 | #if defined(WIN64EXCEPTIONS) && defined(_DEBUG) | 
|---|
| 320 | if ((m_flags & Ex_FlagsAreReadOnly) || (m_debugFlags & Ex_FlagsAreReadOnly)) | 
|---|
| 321 | { | 
|---|
| 322 | _ASSERTE(! "Tried to update read-only flags!"); | 
|---|
| 323 | } | 
|---|
| 324 | #endif // defined(WIN64EXCEPTIONS) && defined(_DEBUG) | 
|---|
| 325 | } | 
|---|
| 326 |  | 
|---|
| 327 | void Init() | 
|---|
| 328 | { | 
|---|
| 329 | m_flags = 0; | 
|---|
| 330 | #ifdef _DEBUG | 
|---|
| 331 | m_debugFlags = 0; | 
|---|
| 332 | #endif // _DEBUG | 
|---|
| 333 | } | 
|---|
| 334 |  | 
|---|
| 335 | BOOL IsRethrown()      { LIMITED_METHOD_CONTRACT; return m_flags & Ex_IsRethrown; } | 
|---|
| 336 | void SetIsRethrown()   { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_IsRethrown; } | 
|---|
| 337 | void ResetIsRethrown() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_IsRethrown; } | 
|---|
| 338 |  | 
|---|
| 339 | BOOL UnwindHasStarted()      { LIMITED_METHOD_CONTRACT; return m_flags & Ex_UnwindHasStarted; } | 
|---|
| 340 | void SetUnwindHasStarted()   { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_UnwindHasStarted; } | 
|---|
| 341 | void ResetUnwindHasStarted() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_UnwindHasStarted; } | 
|---|
| 342 |  | 
|---|
| 343 | BOOL UnwindingToFindResumeFrame()      { LIMITED_METHOD_CONTRACT; return m_flags & Ex_UnwindingToFindResumeFrame; } | 
|---|
| 344 | void SetUnwindingToFindResumeFrame()   { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_UnwindingToFindResumeFrame; } | 
|---|
| 345 | void ResetUnwindingToFindResumeFrame() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_UnwindingToFindResumeFrame; } | 
|---|
| 346 |  | 
|---|
| 347 | BOOL UseExInfoForStackwalk()      { LIMITED_METHOD_DAC_CONTRACT; return m_flags & Ex_UseExInfoForStackwalk; } | 
|---|
| 348 | void SetUseExInfoForStackwalk()   { LIMITED_METHOD_DAC_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_UseExInfoForStackwalk; } | 
|---|
| 349 | void ResetUseExInfoForStackwalk() { LIMITED_METHOD_DAC_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_UseExInfoForStackwalk; } | 
|---|
| 350 |  | 
|---|
| 351 | #ifdef _DEBUG | 
|---|
| 352 | BOOL ReversePInvokeEscapingException()      { LIMITED_METHOD_DAC_CONTRACT; return m_debugFlags & Ex_RPInvokeEscapingException; } | 
|---|
| 353 | void SetReversePInvokeEscapingException()   { LIMITED_METHOD_DAC_CONTRACT; AssertIfReadOnly(); m_debugFlags |= Ex_RPInvokeEscapingException; } | 
|---|
| 354 | void ResetReversePInvokeEscapingException() { LIMITED_METHOD_DAC_CONTRACT; AssertIfReadOnly(); m_debugFlags &= ~Ex_RPInvokeEscapingException; } | 
|---|
| 355 | #endif // _DEBUG | 
|---|
| 356 |  | 
|---|
| 357 | #ifdef DEBUGGING_SUPPORTED | 
|---|
| 358 | BOOL SentDebugUserFirstChance()    { LIMITED_METHOD_CONTRACT; return m_flags & Ex_SentDebugUserFirstChance; } | 
|---|
| 359 | void SetSentDebugUserFirstChance() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_SentDebugUserFirstChance; } | 
|---|
| 360 |  | 
|---|
| 361 | BOOL SentDebugFirstChance()    { LIMITED_METHOD_CONTRACT; return m_flags & Ex_SentDebugFirstChance; } | 
|---|
| 362 | void SetSentDebugFirstChance() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_SentDebugFirstChance; } | 
|---|
| 363 |  | 
|---|
| 364 | BOOL SentDebugUnwindBegin()    { LIMITED_METHOD_CONTRACT; return m_flags & Ex_SentDebugUnwindBegin; } | 
|---|
| 365 | void SetSentDebugUnwindBegin() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_SentDebugUnwindBegin; } | 
|---|
| 366 |  | 
|---|
| 367 | BOOL DebugCatchHandlerFound()    { LIMITED_METHOD_CONTRACT; return m_flags & Ex_DebugCatchHandlerFound; } | 
|---|
| 368 | void SetDebugCatchHandlerFound() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_DebugCatchHandlerFound; } | 
|---|
| 369 |  | 
|---|
| 370 | BOOL SentDebugUnhandled()    { LIMITED_METHOD_CONTRACT; return m_flags & Ex_SentDebugUnhandled; } | 
|---|
| 371 | void SetSentDebugUnhandled() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_SentDebugUnhandled; } | 
|---|
| 372 |  | 
|---|
| 373 | BOOL IsUnhandled()    { LIMITED_METHOD_CONTRACT; return m_flags & Ex_IsUnhandled; } | 
|---|
| 374 | void SetUnhandled() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_IsUnhandled; } | 
|---|
| 375 |  | 
|---|
| 376 | BOOL DebuggerInterceptNotPossible()    { LIMITED_METHOD_CONTRACT; return m_flags & Ex_DebuggerInterceptNotPossible; } | 
|---|
| 377 | void SetDebuggerInterceptNotPossible() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_DebuggerInterceptNotPossible; } | 
|---|
| 378 |  | 
|---|
| 379 | BOOL DebuggerInterceptInfo()    { LIMITED_METHOD_DAC_CONTRACT; return m_flags & Ex_DebuggerInterceptInfo; } | 
|---|
| 380 | void SetDebuggerInterceptInfo() { LIMITED_METHOD_DAC_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_DebuggerInterceptInfo; } | 
|---|
| 381 | #endif | 
|---|
| 382 |  | 
|---|
| 383 | BOOL WasThrownByUs()      { LIMITED_METHOD_CONTRACT; return m_flags & Ex_WasThrownByUs; } | 
|---|
| 384 | void SetWasThrownByUs()   { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_WasThrownByUs; } | 
|---|
| 385 | void ResetWasThrownByUs() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_WasThrownByUs; } | 
|---|
| 386 |  | 
|---|
| 387 | BOOL GotWatsonBucketDetails()      { LIMITED_METHOD_CONTRACT; return m_flags & Ex_GotWatsonBucketInfo; } | 
|---|
| 388 | void SetGotWatsonBucketDetails()   { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags |= Ex_GotWatsonBucketInfo; } | 
|---|
| 389 | void ResetGotWatsonBucketDetails() { LIMITED_METHOD_CONTRACT; AssertIfReadOnly(); m_flags &= ~Ex_GotWatsonBucketInfo; } | 
|---|
| 390 |  | 
|---|
| 391 | private: | 
|---|
| 392 | enum | 
|---|
| 393 | { | 
|---|
| 394 | Ex_IsRethrown                   = 0x00000001, | 
|---|
| 395 | Ex_UnwindingToFindResumeFrame   = 0x00000002, | 
|---|
| 396 | Ex_UnwindHasStarted             = 0x00000004, | 
|---|
| 397 | Ex_UseExInfoForStackwalk        = 0x00000008,        // Use this ExInfo to unwind a fault (AV, zerodiv) back to managed code? | 
|---|
| 398 |  | 
|---|
| 399 | #ifdef DEBUGGING_SUPPORTED | 
|---|
| 400 | Ex_SentDebugUserFirstChance     = 0x00000010, | 
|---|
| 401 | Ex_SentDebugFirstChance         = 0x00000020, | 
|---|
| 402 | Ex_SentDebugUnwindBegin         = 0x00000040, | 
|---|
| 403 | Ex_DebugCatchHandlerFound       = 0x00000080, | 
|---|
| 404 | Ex_SentDebugUnhandled           = 0x00000100, | 
|---|
| 405 | Ex_DebuggerInterceptInfo        = 0x00000200, | 
|---|
| 406 | Ex_DebuggerInterceptNotPossible = 0x00000400, | 
|---|
| 407 | Ex_IsUnhandled                  = 0x00000800, | 
|---|
| 408 | #endif | 
|---|
| 409 | // Unused                       = 0x00001000, | 
|---|
| 410 |  | 
|---|
| 411 | Ex_WasThrownByUs                = 0x00002000, | 
|---|
| 412 |  | 
|---|
| 413 | Ex_GotWatsonBucketInfo          = 0x00004000, | 
|---|
| 414 |  | 
|---|
| 415 | #if defined(WIN64EXCEPTIONS) && defined(_DEBUG) | 
|---|
| 416 | Ex_FlagsAreReadOnly             = 0x80000000 | 
|---|
| 417 | #endif // defined(WIN64EXCEPTIONS) && defined(_DEBUG) | 
|---|
| 418 |  | 
|---|
| 419 | }; | 
|---|
| 420 |  | 
|---|
| 421 | UINT32 m_flags; | 
|---|
| 422 |  | 
|---|
| 423 | #ifdef _DEBUG | 
|---|
| 424 | enum | 
|---|
| 425 | { | 
|---|
| 426 | Ex_RPInvokeEscapingException    = 0x40000000 | 
|---|
| 427 | }; | 
|---|
| 428 | UINT32 m_debugFlags; | 
|---|
| 429 | #endif // _DEBUG | 
|---|
| 430 | }; | 
|---|
| 431 |  | 
|---|
| 432 | //------------------------------------------------------------------------------ | 
|---|
| 433 | // Error reporting (unhandled exception, fatal error, user breakpoint | 
|---|
| 434 | class TypeOfReportedError | 
|---|
| 435 | { | 
|---|
| 436 | public: | 
|---|
| 437 | enum Type {INVALID, UnhandledException, FatalError, UserBreakpoint, NativeThreadUnhandledException, NativeBreakpoint, StackOverflowException}; | 
|---|
| 438 |  | 
|---|
| 439 | TypeOfReportedError(Type t) : m_type(t) {} | 
|---|
| 440 |  | 
|---|
| 441 | BOOL IsUnhandledException() { LIMITED_METHOD_CONTRACT; return (m_type == UnhandledException) || (m_type == NativeThreadUnhandledException) || (m_type == StackOverflowException); } | 
|---|
| 442 | BOOL IsFatalError() { return (m_type == FatalError); } | 
|---|
| 443 | BOOL IsUserBreakpoint() {return (m_type == UserBreakpoint); } | 
|---|
| 444 | BOOL IsBreakpoint() {return (m_type == UserBreakpoint) || (m_type == NativeBreakpoint); } | 
|---|
| 445 | BOOL IsException() { LIMITED_METHOD_CONTRACT; return IsUnhandledException() || (m_type == NativeBreakpoint) || (m_type == StackOverflowException); } | 
|---|
| 446 |  | 
|---|
| 447 | Type GetType() { return m_type; } | 
|---|
| 448 | void SetType(Type t) { m_type = t; } | 
|---|
| 449 |  | 
|---|
| 450 | private: | 
|---|
| 451 | Type m_type; | 
|---|
| 452 | }; | 
|---|
| 453 |  | 
|---|
| 454 |  | 
|---|
| 455 | #ifndef FEATURE_PAL | 
|---|
| 456 | // This class is used to track Watson bucketing information for an exception. | 
|---|
| 457 | typedef DPTR(class EHWatsonBucketTracker) PTR_EHWatsonBucketTracker; | 
|---|
| 458 | class EHWatsonBucketTracker | 
|---|
| 459 | { | 
|---|
| 460 | private: | 
|---|
| 461 | struct | 
|---|
| 462 | { | 
|---|
| 463 | PTR_VOID m_pUnhandledBuckets; | 
|---|
| 464 | UINT_PTR    m_UnhandledIp; | 
|---|
| 465 | } m_WatsonUnhandledInfo; | 
|---|
| 466 |  | 
|---|
| 467 | #ifdef _DEBUG | 
|---|
| 468 | enum | 
|---|
| 469 | { | 
|---|
| 470 | // Bucket details were captured for ThreadAbort | 
|---|
| 471 | Wb_CapturedForThreadAbort = 1, | 
|---|
| 472 |  | 
|---|
| 473 | // Bucket details were captured at AD Transition | 
|---|
| 474 | Wb_CapturedAtADTransition = 2, | 
|---|
| 475 |  | 
|---|
| 476 | // Bucket details were captured during Reflection invocation | 
|---|
| 477 | Wb_CapturedAtReflectionInvocation = 4 | 
|---|
| 478 | }; | 
|---|
| 479 |  | 
|---|
| 480 | DWORD m_DebugFlags; | 
|---|
| 481 | #endif // _DEBUG | 
|---|
| 482 |  | 
|---|
| 483 | public: | 
|---|
| 484 | EHWatsonBucketTracker(); | 
|---|
| 485 | void Init(); | 
|---|
| 486 | void CopyEHWatsonBucketTracker(const EHWatsonBucketTracker& srcTracker); | 
|---|
| 487 | void CopyBucketsFromThrowable(OBJECTREF oThrowable); | 
|---|
| 488 | void SaveIpForWatsonBucket(UINT_PTR ip); | 
|---|
| 489 | UINT_PTR RetrieveWatsonBucketIp(); | 
|---|
| 490 | PTR_VOID RetrieveWatsonBuckets(); | 
|---|
| 491 | void ClearWatsonBucketDetails(); | 
|---|
| 492 | void CaptureUnhandledInfoForWatson(TypeOfReportedError tore, Thread * pThread, OBJECTREF * pThrowable); | 
|---|
| 493 |  | 
|---|
| 494 | #ifdef _DEBUG | 
|---|
| 495 | void ResetFlags()                  { LIMITED_METHOD_CONTRACT; m_DebugFlags = 0; } | 
|---|
| 496 | BOOL CapturedForThreadAbort()      { LIMITED_METHOD_CONTRACT; return m_DebugFlags & Wb_CapturedForThreadAbort; } | 
|---|
| 497 | void SetCapturedForThreadAbort()   { LIMITED_METHOD_CONTRACT; m_DebugFlags |= Wb_CapturedForThreadAbort; } | 
|---|
| 498 | void ResetCapturedForThreadAbort() { LIMITED_METHOD_CONTRACT; m_DebugFlags &= ~Wb_CapturedForThreadAbort; } | 
|---|
| 499 |  | 
|---|
| 500 | BOOL CapturedAtADTransition()      { LIMITED_METHOD_CONTRACT; return m_DebugFlags & Wb_CapturedAtADTransition; } | 
|---|
| 501 | void SetCapturedAtADTransition()   { LIMITED_METHOD_CONTRACT; m_DebugFlags |= Wb_CapturedAtADTransition; } | 
|---|
| 502 | void ResetCapturedAtADTransition() { LIMITED_METHOD_CONTRACT; m_DebugFlags &= ~Wb_CapturedAtADTransition; } | 
|---|
| 503 |  | 
|---|
| 504 | BOOL CapturedAtReflectionInvocation()      { LIMITED_METHOD_CONTRACT; return m_DebugFlags & Wb_CapturedAtReflectionInvocation; } | 
|---|
| 505 | void SetCapturedAtReflectionInvocation()   { LIMITED_METHOD_CONTRACT; m_DebugFlags |= Wb_CapturedAtReflectionInvocation; } | 
|---|
| 506 | void ResetCapturedAtReflectionInvocation() { LIMITED_METHOD_CONTRACT; m_DebugFlags &= ~Wb_CapturedAtReflectionInvocation; } | 
|---|
| 507 | #endif // _DEBUG | 
|---|
| 508 | }; | 
|---|
| 509 |  | 
|---|
| 510 | void SetStateForWatsonBucketing(BOOL fIsRethrownException, OBJECTHANDLE ohOriginalException); | 
|---|
| 511 | BOOL CopyWatsonBucketsToThrowable(PTR_VOID pUnmanagedBuckets, OBJECTREF oTargetThrowable = NULL); | 
|---|
| 512 | void CopyWatsonBucketsFromThrowableToCurrentThrowable(OBJECTREF oThrowableFrom); | 
|---|
| 513 | void CopyWatsonBucketsBetweenThrowables(OBJECTREF oThrowableFrom, OBJECTREF oThrowableTo = NULL); | 
|---|
| 514 | void SetupInitialThrowBucketDetails(UINT_PTR adjustedIp); | 
|---|
| 515 | BOOL SetupWatsonBucketsForFailFast(EXCEPTIONREF refException); | 
|---|
| 516 | void SetupWatsonBucketsForUEF(BOOL fUseLastThrownObject); | 
|---|
| 517 | BOOL SetupWatsonBucketsForEscapingPreallocatedExceptions(); | 
|---|
| 518 | BOOL SetupWatsonBucketsForNonPreallocatedExceptions(OBJECTREF oThrowable = NULL); | 
|---|
| 519 | PTR_EHWatsonBucketTracker GetWatsonBucketTrackerForPreallocatedException(OBJECTREF oPreAllocThrowable, BOOL fCaptureBucketsIfNotPresent, | 
|---|
| 520 | BOOL fStartSearchFromPreviousTracker = FALSE); | 
|---|
| 521 | BOOL IsThrowableThreadAbortException(OBJECTREF oThrowable); | 
|---|
| 522 | #endif // !FEATURE_PAL | 
|---|
| 523 |  | 
|---|
| 524 | #endif // __ExStateCommon_h__ | 
|---|
| 525 |  | 
|---|