| File: Contracts\Exception_1.cs | Web Access |
| Project: src\runtime\src\native\managed\cdac\Microsoft.Diagnostics.DataContractReader.Contracts\Microsoft.Diagnostics.DataContractReader.Contracts.csproj (Microsoft.Diagnostics.DataContractReader.Contracts) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.Collections.Generic; namespace Microsoft.Diagnostics.DataContractReader.Contracts; internal readonly struct Exception_1 : IException { // STEF_LAST_FRAME_FROM_FOREIGN_STACK_TRACE flag value from src/coreclr/vm/clrex.h. private const int STEF_LAST_FRAME_FROM_FOREIGN_STACK_TRACE = 0x0001; private readonly Target _target; internal Exception_1(Target target) { _target = target; } TargetPointer IException.GetNestedExceptionInfo(TargetPointer exceptionInfoAddr, out TargetPointer nextNestedExceptionInfo, out TargetPointer thrownObjectHandle) { Data.ExceptionInfo exceptionInfo = _target.ProcessedData.GetOrAdd<Data.ExceptionInfo>(exceptionInfoAddr); nextNestedExceptionInfo = exceptionInfo.PreviousNestedInfo; // ThrownObject is a direct object pointer stored in ExInfo::m_exception. // Return the address of the field as a "handle" - reading through it yields the // exception Object*. This has the same lifetime as the ExInfo (both are invalidated // when PopExInfos calls ReleaseResources). See dacimpl.h for the equivalent native // DAC documentation. Target.TypeInfo type = _target.GetTypeInfo(DataType.ExceptionInfo); thrownObjectHandle = exceptionInfoAddr + (ulong)type.Fields[nameof(Data.ExceptionInfo.ThrownObject)].Offset; return exceptionInfo.ThrownObject; } ExceptionData IException.GetExceptionData(TargetPointer exceptionAddr) { Data.Exception exception = _target.ProcessedData.GetOrAdd<Data.Exception>(exceptionAddr); return new ExceptionData( exception.Message, exception.InnerException, exception.StackTrace, exception.WatsonBuckets, exception.StackTraceString, exception.RemoteStackTraceString, exception.HResult, exception.XCode); } IEnumerable<ExceptionStackFrameInfo> IException.GetExceptionStackFrames(TargetPointer exceptionAddr) { Data.Exception exception = _target.ProcessedData.GetOrAdd<Data.Exception>(exceptionAddr); TargetPointer stackTraceObj = exception.StackTrace; if (stackTraceObj == TargetPointer.Null) yield break; // Path 1: the stack trace object's MethodTable ContainsGCPointers. The object is a // combined object[] whose first slot is the actual stack-trace I1Array and // whose subsequent slots are the keep-alive references. We unwrap to slot 0. // Path 2: the stack trace object is itself the I1Array payload. IObject objectContract = _target.Contracts.Object; IRuntimeTypeSystem rtsContract = _target.Contracts.RuntimeTypeSystem; TargetPointer mt = objectContract.GetMethodTableAddress(stackTraceObj); if (mt == TargetPointer.Null) throw new InvalidOperationException($"Stack trace object 0x{stackTraceObj.Value:x} has no MethodTable."); TypeHandle stackTraceHandle = rtsContract.GetTypeHandle(mt); TargetPointer i1ArrayAddr; if (rtsContract.ContainsGCPointers(stackTraceHandle)) { // Combined PTRArray; slot 0 holds the I1Array pointer. Data.Array combinedArray = _target.ProcessedData.GetOrAdd<Data.Array>(stackTraceObj); i1ArrayAddr = _target.ReadPointer(combinedArray.DataPointer); } else { i1ArrayAddr = stackTraceObj; } if (i1ArrayAddr == TargetPointer.Null) yield break; Data.Array i1Array = _target.ProcessedData.GetOrAdd<Data.Array>(i1ArrayAddr); TargetPointer payload = i1Array.DataPointer; Data.StackTraceArrayHeader header = _target.ProcessedData.GetOrAdd<Data.StackTraceArrayHeader>(payload); uint frameCount = header.Size; if (frameCount == 0) yield break; Target.TypeInfo elementTypeInfo = _target.GetTypeInfo(DataType.StackTraceElement); ulong elementSize = elementTypeInfo.Size!.Value; uint headerSize = _target.GetTypeInfo(DataType.StackTraceArrayHeader).Size!.Value; TargetPointer cursor = payload + headerSize; for (uint i = 0; i < frameCount; i++) { Data.StackTraceElement element = _target.ProcessedData.GetOrAdd<Data.StackTraceElement>(cursor); yield return new ExceptionStackFrameInfo( element.Ip, element.MethodDesc, (element.Flags & STEF_LAST_FRAME_FROM_FOREIGN_STACK_TRACE) != 0); cursor += elementSize; } } }