private static void SerializeExceptionsForDump(Exception currentException, IntPtr exceptionCCWPtr, LowLevelList <byte[]> serializedExceptions) { const UInt32 NoInnerExceptionValue = 0xFFFFFFFF; // Approximate upper size limit for the serialized exceptions (but we'll always serialize currentException) // If we hit the limit, because we serialize in arbitrary order, there may be missing InnerExceptions or nested exceptions. const int MaxBufferSize = 20000; int nExceptions; RuntimeImports.RhGetExceptionsForCurrentThread(null, out nExceptions); Exception[] curThreadExceptions = new Exception[nExceptions]; RuntimeImports.RhGetExceptionsForCurrentThread(curThreadExceptions, out nExceptions); LowLevelList <Exception> exceptions = new LowLevelList <Exception>(curThreadExceptions); LowLevelList <Exception> nonThrownInnerExceptions = new LowLevelList <Exception>(); uint currentThreadId = Interop.mincore.GetCurrentThreadId(); // Reset nesting levels for exceptions on this thread that might not be currently in flight foreach (ExceptionData exceptionData in s_exceptionDataTable.GetValues()) { if (exceptionData.ExceptionMetadata.ThreadId == currentThreadId) { exceptionData.ExceptionMetadata.NestingLevel = -1; } } // Find all inner exceptions, even if they're not currently being handled for (int i = 0; i < exceptions.Count; i++) { if (exceptions[i].InnerException != null && !exceptions.Contains(exceptions[i].InnerException)) { exceptions.Add(exceptions[i].InnerException); nonThrownInnerExceptions.Add(exceptions[i].InnerException); } } int currentNestingLevel = curThreadExceptions.Length - 1; // Populate exception data for all exceptions interesting to this thread. // Whether or not there was previously data for that object, it might have changed. for (int i = 0; i < exceptions.Count; i++) { ExceptionData exceptionData = s_exceptionDataTable.GetOrCreateValue(exceptions[i]); exceptionData.ExceptionMetadata.ExceptionId = (UInt32)System.Threading.Interlocked.Increment(ref s_currentExceptionId); if (exceptionData.ExceptionMetadata.ExceptionId == NoInnerExceptionValue) { exceptionData.ExceptionMetadata.ExceptionId = (UInt32)System.Threading.Interlocked.Increment(ref s_currentExceptionId); } exceptionData.ExceptionMetadata.ThreadId = currentThreadId; // Only include nesting information for exceptions that were thrown on this thread if (!nonThrownInnerExceptions.Contains(exceptions[i])) { exceptionData.ExceptionMetadata.NestingLevel = currentNestingLevel; currentNestingLevel--; } else { exceptionData.ExceptionMetadata.NestingLevel = -1; } // Only match the CCW pointer up to the current exception if (Object.ReferenceEquals(exceptions[i], currentException)) { exceptionData.ExceptionMetadata.ExceptionCCWPtr = exceptionCCWPtr; } byte[] serializedEx = exceptions[i].SerializeForDump(); exceptionData.SerializedExceptionData = serializedEx; } // Populate inner exception ids now that we have all of them in the table for (int i = 0; i < exceptions.Count; i++) { ExceptionData exceptionData; if (!s_exceptionDataTable.TryGetValue(exceptions[i], out exceptionData)) { // This shouldn't happen, but we can't meaningfully throw here continue; } if (exceptions[i].InnerException != null) { ExceptionData innerExceptionData; if (s_exceptionDataTable.TryGetValue(exceptions[i].InnerException, out innerExceptionData)) { exceptionData.ExceptionMetadata.InnerExceptionId = innerExceptionData.ExceptionMetadata.ExceptionId; } } else { exceptionData.ExceptionMetadata.InnerExceptionId = NoInnerExceptionValue; } } int totalSerializedExceptionSize = 0; // Make sure we include the current exception, regardless of buffer size ExceptionData currentExceptionData = null; if (s_exceptionDataTable.TryGetValue(currentException, out currentExceptionData)) { byte[] serializedExceptionData = currentExceptionData.Serialize(); serializedExceptions.Add(serializedExceptionData); totalSerializedExceptionSize = serializedExceptionData.Length; } checked { foreach (ExceptionData exceptionData in s_exceptionDataTable.GetValues()) { // Already serialized currentException if (currentExceptionData != null && exceptionData.ExceptionMetadata.ExceptionId == currentExceptionData.ExceptionMetadata.ExceptionId) { continue; } byte[] serializedExceptionData = exceptionData.Serialize(); if (totalSerializedExceptionSize + serializedExceptionData.Length >= MaxBufferSize) { break; } serializedExceptions.Add(serializedExceptionData); totalSerializedExceptionSize += serializedExceptionData.Length; } } }