mirror of
https://github.com/VSadov/Satori.git
synced 2025-06-09 17:44:48 +09:00
[cdac] Implement ISOSDacInterface2::GetObjectExceptionData (#104343)
- Make cDac implement `ISOSDacInterface2` - Add `Exception` (managed type) to data descriptor - Add `GetExceptionData` to `Exception` contract which gets all the data that SOS-DAC API uses
This commit is contained in:
parent
5795e8c056
commit
e733c2f227
12 changed files with 218 additions and 17 deletions
|
@ -4,25 +4,53 @@ This contract is for getting information about exceptions in the process.
|
|||
|
||||
## APIs of contract
|
||||
|
||||
```csharp
|
||||
record struct ExceptionData(
|
||||
TargetPointer Message,
|
||||
TargetPointer InnerException,
|
||||
TargetPointer StackTrace,
|
||||
TargetPointer WatsonBuckets,
|
||||
TargetPointer StackTraceString,
|
||||
TargetPointer RemoteStackTraceString,
|
||||
int HResult,
|
||||
int XCode);
|
||||
```
|
||||
|
||||
``` csharp
|
||||
TargetPointer GetExceptionInfo(TargetPointer exception, out TargetPointer nextNestedException);
|
||||
TargetPointer GetNestedExceptionInfo(TargetPointer exceptionInfoAddr, out TargetPointer nextNestedExceptionInfo);
|
||||
ExceptionData GetExceptionData(TargetPointer exceptionAddr)
|
||||
```
|
||||
|
||||
## Version 1
|
||||
|
||||
Data descriptors used:
|
||||
- `ExceptionInfo`
|
||||
- `Exception`
|
||||
|
||||
``` csharp
|
||||
TargetPointer GetExceptionInfo(TargetPointer exception, out TargetPointer nextNestedException)
|
||||
TargetPointer GetNestedExceptionInfo(TargetPointer exceptionInfoAddr, out TargetPointer nextNestedExceptionInfo)
|
||||
{
|
||||
if (exception == TargetPointer.Null)
|
||||
if (exceptionInfo == TargetPointer.Null)
|
||||
throw new InvalidArgumentException();
|
||||
|
||||
nextNestedException = target.ReadPointer(address + /* ExceptionInfo::PreviousNestedInfo offset*/);
|
||||
TargetPointer thrownObjHandle = target.ReadPointer(address + /* ExceptionInfo::ThrownObject offset */);
|
||||
nextNestedException = target.ReadPointer(exceptionInfo + /* ExceptionInfo::PreviousNestedInfo offset*/);
|
||||
TargetPointer thrownObjHandle = target.ReadPointer(exceptionInfo + /* ExceptionInfo::ThrownObject offset */);
|
||||
return = thrownObjHandle != TargetPointer.Null
|
||||
? target.ReadPointer(thrownObjHandle)
|
||||
: TargetPointer.Null;
|
||||
}
|
||||
|
||||
ExceptionData GetExceptionData(TargetPointer exceptionAddr)
|
||||
{
|
||||
return new ExceptionData(
|
||||
target.ReadPointer(exceptionAddr + /* Exception::Message offset */),
|
||||
target.ReadPointer(exceptionAddr + /* Exception::InnerException offset */),
|
||||
target.ReadPointer(exceptionAddr + /* Exception::StackTrace offset */),
|
||||
target.ReadPointer(exceptionAddr + /* Exception::WatsonBuckets offset */),
|
||||
target.ReadPointer(exceptionAddr + /* Exception::StackTraceString offset */),
|
||||
target.ReadPointer(exceptionAddr + /* Exception::RemoteStackTraceString offset */),
|
||||
target.Read<int>(exceptionAddr + /* Exception::HResult offset */),
|
||||
target.Read<int>(exceptionAddr + /* Exception::XCode offset */),
|
||||
);
|
||||
}
|
||||
```
|
||||
|
|
|
@ -5512,6 +5512,7 @@ ClrDataAccess::Initialize(void)
|
|||
// Get SOS interfaces from the cDAC if available.
|
||||
IUnknown* unk = m_cdac.SosInterface();
|
||||
(void)unk->QueryInterface(__uuidof(ISOSDacInterface), (void**)&m_cdacSos);
|
||||
(void)unk->QueryInterface(__uuidof(ISOSDacInterface2), (void**)&m_cdacSos2);
|
||||
(void)unk->QueryInterface(__uuidof(ISOSDacInterface9), (void**)&m_cdacSos9);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1235,6 +1235,7 @@ public:
|
|||
HRESULT GetNestedExceptionDataImpl(CLRDATA_ADDRESS exception, CLRDATA_ADDRESS *exceptionObject, CLRDATA_ADDRESS *nextNestedException);
|
||||
HRESULT GetMethodTableDataImpl(CLRDATA_ADDRESS mt, struct DacpMethodTableData *data);
|
||||
HRESULT GetMethodTableForEEClassImpl (CLRDATA_ADDRESS eeClassReallyMT, CLRDATA_ADDRESS *value);
|
||||
HRESULT GetObjectExceptionDataImpl(CLRDATA_ADDRESS objAddr, struct DacpExceptionObjectData *data);
|
||||
|
||||
BOOL IsExceptionFromManagedCode(EXCEPTION_RECORD * pExceptionRecord);
|
||||
#ifndef TARGET_UNIX
|
||||
|
@ -1424,6 +1425,7 @@ public:
|
|||
|
||||
CDAC m_cdac;
|
||||
NonVMComHolder<ISOSDacInterface> m_cdacSos;
|
||||
NonVMComHolder<ISOSDacInterface2> m_cdacSos2;
|
||||
NonVMComHolder<ISOSDacInterface9> m_cdacSos9;
|
||||
|
||||
#ifdef FEATURE_MINIMETADATA_IN_TRIAGEDUMPS
|
||||
|
|
|
@ -4647,8 +4647,42 @@ HRESULT ClrDataAccess::GetObjectExceptionData(CLRDATA_ADDRESS objAddr, struct Da
|
|||
|
||||
SOSDacEnter();
|
||||
|
||||
PTR_ExceptionObject pObj = dac_cast<PTR_ExceptionObject>(TO_TADDR(objAddr));
|
||||
if (m_cdacSos2 != NULL)
|
||||
{
|
||||
hr = m_cdacSos2->GetObjectExceptionData(objAddr, data);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
hr = GetObjectExceptionDataImpl(objAddr, data);
|
||||
}
|
||||
#ifdef _DEBUG
|
||||
else
|
||||
{
|
||||
DacpExceptionObjectData dataLocal;
|
||||
HRESULT hrLocal = GetObjectExceptionDataImpl(objAddr, &dataLocal);
|
||||
_ASSERTE(hr == hrLocal);
|
||||
_ASSERTE(data->Message == dataLocal.Message);
|
||||
_ASSERTE(data->InnerException == dataLocal.InnerException);
|
||||
_ASSERTE(data->StackTrace == dataLocal.StackTrace);
|
||||
_ASSERTE(data->WatsonBuckets == dataLocal.WatsonBuckets);
|
||||
_ASSERTE(data->StackTraceString == dataLocal.StackTraceString);
|
||||
_ASSERTE(data->RemoteStackTraceString == dataLocal.RemoteStackTraceString);
|
||||
_ASSERTE(data->HResult == dataLocal.HResult);
|
||||
_ASSERTE(data->XCode == dataLocal.XCode);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
hr = GetObjectExceptionDataImpl(objAddr, data);
|
||||
}
|
||||
|
||||
SOSDacLeave();
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT ClrDataAccess::GetObjectExceptionDataImpl(CLRDATA_ADDRESS objAddr, struct DacpExceptionObjectData *data)
|
||||
{
|
||||
PTR_ExceptionObject pObj = dac_cast<PTR_ExceptionObject>(TO_TADDR(objAddr));
|
||||
data->Message = TO_CDADDR(dac_cast<TADDR>(pObj->GetMessage()));
|
||||
data->InnerException = TO_CDADDR(dac_cast<TADDR>(pObj->GetInnerException()));
|
||||
data->StackTrace = TO_CDADDR(dac_cast<TADDR>(pObj->GetStackTraceArrayObject()));
|
||||
|
@ -4657,10 +4691,7 @@ HRESULT ClrDataAccess::GetObjectExceptionData(CLRDATA_ADDRESS objAddr, struct Da
|
|||
data->RemoteStackTraceString = TO_CDADDR(dac_cast<TADDR>(pObj->GetRemoteStackTraceString()));
|
||||
data->HResult = pObj->GetHResult();
|
||||
data->XCode = pObj->GetXCode();
|
||||
|
||||
SOSDacLeave();
|
||||
|
||||
return hr;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
HRESULT ClrDataAccess::IsRCWDCOMProxy(CLRDATA_ADDRESS rcwAddr, BOOL* isDCOMProxy)
|
||||
|
|
|
@ -141,6 +141,21 @@ CDAC_TYPE_FIELD(GCAllocContext, /*pointer*/, Pointer, offsetof(gc_alloc_context,
|
|||
CDAC_TYPE_FIELD(GCAllocContext, /*pointer*/, Limit, offsetof(gc_alloc_context, alloc_limit))
|
||||
CDAC_TYPE_END(GCAllocContext)
|
||||
|
||||
// Exception
|
||||
|
||||
// Use exact managed type field names for the descriptor as field names often can't change due to binary serialization or implicit diagnostic contracts
|
||||
CDAC_TYPE_BEGIN(Exception)
|
||||
CDAC_TYPE_INDETERMINATE(Exception)
|
||||
CDAC_TYPE_FIELD(Exception, /*pointer*/, _message, cdac_offsets<ExceptionObject>::_message)
|
||||
CDAC_TYPE_FIELD(Exception, /*pointer*/, _innerException, cdac_offsets<ExceptionObject>::_innerException)
|
||||
CDAC_TYPE_FIELD(Exception, /*pointer*/, _stackTrace, cdac_offsets<ExceptionObject>::_stackTrace)
|
||||
CDAC_TYPE_FIELD(Exception, /*pointer*/, _watsonBuckets, cdac_offsets<ExceptionObject>::_watsonBuckets)
|
||||
CDAC_TYPE_FIELD(Exception, /*pointer*/, _stackTraceString, cdac_offsets<ExceptionObject>::_stackTraceString)
|
||||
CDAC_TYPE_FIELD(Exception, /*pointer*/, _remoteStackTraceString, cdac_offsets<ExceptionObject>::_remoteStackTraceString)
|
||||
CDAC_TYPE_FIELD(Exception, /*int32*/, _HResult, cdac_offsets<ExceptionObject>::_HResult)
|
||||
CDAC_TYPE_FIELD(Exception, /*int32*/, _xcode, cdac_offsets<ExceptionObject>::_xcode)
|
||||
CDAC_TYPE_END(Exception)
|
||||
|
||||
CDAC_TYPE_BEGIN(ExceptionInfo)
|
||||
CDAC_TYPE_INDETERMINATE(ExceptionInfo)
|
||||
#if FEATURE_EH_FUNCLETS
|
||||
|
@ -152,6 +167,7 @@ CDAC_TYPE_FIELD(PreviousNestedInfo, /*pointer*/, PreviousNestedInfo, offsetof(Ex
|
|||
#endif
|
||||
CDAC_TYPE_END(ExceptionInfo)
|
||||
|
||||
|
||||
CDAC_TYPE_BEGIN(GCHandle)
|
||||
CDAC_TYPE_SIZE(sizeof(OBJECTHANDLE))
|
||||
CDAC_TYPE_END(GCHandle)
|
||||
|
|
|
@ -2355,6 +2355,21 @@ private:
|
|||
void* _xptrs;
|
||||
INT32 _xcode;
|
||||
INT32 _HResult;
|
||||
|
||||
template<typename T> friend struct ::cdac_offsets;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct cdac_offsets<ExceptionObject>
|
||||
{
|
||||
static constexpr size_t _message = offsetof(ExceptionObject, _message);
|
||||
static constexpr size_t _innerException = offsetof(ExceptionObject, _innerException);
|
||||
static constexpr size_t _stackTrace = offsetof(ExceptionObject, _stackTrace);
|
||||
static constexpr size_t _watsonBuckets = offsetof(ExceptionObject, _watsonBuckets);
|
||||
static constexpr size_t _stackTraceString = offsetof(ExceptionObject, _stackTraceString);
|
||||
static constexpr size_t _remoteStackTraceString = offsetof(ExceptionObject, _remoteStackTraceString);
|
||||
static constexpr size_t _HResult = offsetof(ExceptionObject, _HResult);
|
||||
static constexpr size_t _xcode = offsetof(ExceptionObject, _xcode);
|
||||
};
|
||||
|
||||
// Defined in Contracts.cs
|
||||
|
|
|
@ -5,6 +5,16 @@ using System;
|
|||
|
||||
namespace Microsoft.Diagnostics.DataContractReader.Contracts;
|
||||
|
||||
internal record struct ExceptionData(
|
||||
TargetPointer Message,
|
||||
TargetPointer InnerException,
|
||||
TargetPointer StackTrace,
|
||||
TargetPointer WatsonBuckets,
|
||||
TargetPointer StackTraceString,
|
||||
TargetPointer RemoteStackTraceString,
|
||||
int HResult,
|
||||
int XCode);
|
||||
|
||||
internal interface IException : IContract
|
||||
{
|
||||
static string IContract.Name { get; } = nameof(Exception);
|
||||
|
@ -17,7 +27,8 @@ internal interface IException : IContract
|
|||
};
|
||||
}
|
||||
|
||||
public virtual TargetPointer GetExceptionInfo(TargetPointer exception, out TargetPointer nextNestedException) => throw new NotImplementedException();
|
||||
public virtual TargetPointer GetNestedExceptionInfo(TargetPointer exception, out TargetPointer nextNestedException) => throw new NotImplementedException();
|
||||
public virtual ExceptionData GetExceptionData(TargetPointer managedException) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal readonly struct Exception : IException
|
||||
|
|
|
@ -14,10 +14,24 @@ internal readonly struct Exception_1 : IException
|
|||
_target = target;
|
||||
}
|
||||
|
||||
TargetPointer IException.GetExceptionInfo(TargetPointer exception, out TargetPointer nextNestedException)
|
||||
TargetPointer IException.GetNestedExceptionInfo(TargetPointer exceptionInfoAddr, out TargetPointer nextNestedExceptionInfo)
|
||||
{
|
||||
Data.ExceptionInfo exceptionInfo = _target.ProcessedData.GetOrAdd<Data.ExceptionInfo>(exception);
|
||||
nextNestedException = exceptionInfo.PreviousNestedInfo;
|
||||
Data.ExceptionInfo exceptionInfo = _target.ProcessedData.GetOrAdd<Data.ExceptionInfo>(exceptionInfoAddr);
|
||||
nextNestedExceptionInfo = exceptionInfo.PreviousNestedInfo;
|
||||
return exceptionInfo.ThrownObject.Object;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
33
src/native/managed/cdacreader/src/Data/Exception.cs
Normal file
33
src/native/managed/cdacreader/src/Data/Exception.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
namespace Microsoft.Diagnostics.DataContractReader.Data;
|
||||
|
||||
internal sealed class Exception : IData<Exception>
|
||||
{
|
||||
static Exception IData<Exception>.Create(Target target, TargetPointer address)
|
||||
=> new Exception(target, address);
|
||||
|
||||
public Exception(Target target, TargetPointer address)
|
||||
{
|
||||
Target.TypeInfo type = target.GetTypeInfo(DataType.Exception);
|
||||
|
||||
Message = target.ReadPointer(address + (ulong)type.Fields["_message"].Offset);
|
||||
InnerException = target.ReadPointer(address + (ulong)type.Fields["_innerException"].Offset);
|
||||
StackTrace = target.ReadPointer(address + (ulong)type.Fields["_stackTrace"].Offset);
|
||||
WatsonBuckets = target.ReadPointer(address + (ulong)type.Fields["_watsonBuckets"].Offset);
|
||||
StackTraceString = target.ReadPointer(address + (ulong)type.Fields["_stackTraceString"].Offset);
|
||||
RemoteStackTraceString = target.ReadPointer(address + (ulong)type.Fields["_remoteStackTraceString"].Offset);
|
||||
HResult = target.Read<int>(address + (ulong)type.Fields["_HResult"].Offset);
|
||||
XCode = target.Read<int>(address + (ulong)type.Fields["_xcode"].Offset);
|
||||
}
|
||||
|
||||
public TargetPointer Message { get; init; }
|
||||
public TargetPointer InnerException { get; init; }
|
||||
public TargetPointer StackTrace { get; init; }
|
||||
public TargetPointer WatsonBuckets { get; init; }
|
||||
public TargetPointer StackTraceString { get; init; }
|
||||
public TargetPointer RemoteStackTraceString { get; init; }
|
||||
public int HResult { get; init; }
|
||||
public int XCode { get; init; }
|
||||
}
|
|
@ -23,6 +23,7 @@ public enum DataType
|
|||
Thread,
|
||||
ThreadStore,
|
||||
GCAllocContext,
|
||||
Exception,
|
||||
ExceptionInfo,
|
||||
RuntimeThreadLocals,
|
||||
Module,
|
||||
|
|
|
@ -334,6 +334,30 @@ internal unsafe partial interface ISOSDacInterface
|
|||
int GetFailedAssemblyDisplayName(ulong assembly, uint count, char* name, uint* pNeeded);
|
||||
};
|
||||
|
||||
#pragma warning disable CS0649 // Field is never assigned to, and will always have its default value
|
||||
internal struct DacpExceptionObjectData
|
||||
{
|
||||
public ulong Message;
|
||||
public ulong InnerException;
|
||||
public ulong StackTrace;
|
||||
public ulong WatsonBuckets;
|
||||
public ulong StackTraceString;
|
||||
public ulong RemoteStackTraceString;
|
||||
public int HResult;
|
||||
public int XCode;
|
||||
}
|
||||
#pragma warning restore CS0649 // Field is never assigned to, and will always have its default value
|
||||
|
||||
[GeneratedComInterface]
|
||||
[Guid("A16026EC-96F4-40BA-87FB-5575986FB7AF")]
|
||||
internal unsafe partial interface ISOSDacInterface2
|
||||
{
|
||||
[PreserveSig]
|
||||
int GetObjectExceptionData(ulong objectAddress, DacpExceptionObjectData* data);
|
||||
[PreserveSig]
|
||||
int IsRCWDCOMProxy(ulong rcwAddress, int* inDCOMProxy);
|
||||
}
|
||||
|
||||
[GeneratedComInterface]
|
||||
[Guid("4eca42d8-7e7b-4c8a-a116-7bfbf6929267")]
|
||||
internal partial interface ISOSDacInterface9
|
||||
|
|
|
@ -17,7 +17,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Legacy;
|
|||
/// corresponding error code.
|
||||
/// </remarks>
|
||||
[GeneratedComClass]
|
||||
internal sealed partial class SOSDacImpl : ISOSDacInterface, ISOSDacInterface9
|
||||
internal sealed partial class SOSDacImpl : ISOSDacInterface, ISOSDacInterface2, ISOSDacInterface9
|
||||
{
|
||||
private readonly Target _target;
|
||||
|
||||
|
@ -204,7 +204,7 @@ internal sealed partial class SOSDacImpl : ISOSDacInterface, ISOSDacInterface9
|
|||
try
|
||||
{
|
||||
Contracts.IException contract = _target.Contracts.Exception;
|
||||
TargetPointer exceptionObjectLocal = contract.GetExceptionInfo(exception, out TargetPointer nextNestedExceptionLocal);
|
||||
TargetPointer exceptionObjectLocal = contract.GetNestedExceptionInfo(exception, out TargetPointer nextNestedExceptionLocal);
|
||||
*exceptionObject = exceptionObjectLocal;
|
||||
*nextNestedException = nextNestedExceptionLocal;
|
||||
}
|
||||
|
@ -218,6 +218,30 @@ internal sealed partial class SOSDacImpl : ISOSDacInterface, ISOSDacInterface9
|
|||
|
||||
public unsafe int GetObjectClassName(ulong obj, uint count, char* className, uint* pNeeded) => HResults.E_NOTIMPL;
|
||||
public unsafe int GetObjectData(ulong objAddr, void* data) => HResults.E_NOTIMPL;
|
||||
|
||||
public unsafe int GetObjectExceptionData(ulong objectAddress, DacpExceptionObjectData* data)
|
||||
{
|
||||
try
|
||||
{
|
||||
Contracts.IException contract = _target.Contracts.Exception;
|
||||
Contracts.ExceptionData exceptionData = contract.GetExceptionData(objectAddress);
|
||||
data->Message = exceptionData.Message;
|
||||
data->InnerException = exceptionData.InnerException;
|
||||
data->StackTrace = exceptionData.StackTrace;
|
||||
data->WatsonBuckets = exceptionData.WatsonBuckets;
|
||||
data->StackTraceString = exceptionData.StackTraceString;
|
||||
data->RemoteStackTraceString = exceptionData.RemoteStackTraceString;
|
||||
data->HResult = exceptionData.HResult;
|
||||
data->XCode = exceptionData.XCode;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return ex.HResult;
|
||||
}
|
||||
|
||||
return HResults.S_OK;
|
||||
}
|
||||
|
||||
public unsafe int GetObjectStringData(ulong obj, uint count, char* stringData, uint* pNeeded) => HResults.E_NOTIMPL;
|
||||
public unsafe int GetOOMData(ulong oomAddr, void* data) => HResults.E_NOTIMPL;
|
||||
public unsafe int GetOOMStaticData(void* data) => HResults.E_NOTIMPL;
|
||||
|
@ -301,6 +325,7 @@ internal sealed partial class SOSDacImpl : ISOSDacInterface, ISOSDacInterface9
|
|||
public unsafe int GetTLSIndex(uint* pIndex) => HResults.E_NOTIMPL;
|
||||
public unsafe int GetUsefulGlobals(void* data) => HResults.E_NOTIMPL;
|
||||
public unsafe int GetWorkRequestData(ulong addrWorkRequest, void* data) => HResults.E_NOTIMPL;
|
||||
public unsafe int IsRCWDCOMProxy(ulong rcwAddress, int* inDCOMProxy) => HResults.E_NOTIMPL;
|
||||
public unsafe int TraverseEHInfo(ulong ip, void* pCallback, void* token) => HResults.E_NOTIMPL;
|
||||
public unsafe int TraverseLoaderHeap(ulong loaderHeapAddr, void* pCallback) => HResults.E_NOTIMPL;
|
||||
public unsafe int TraverseModuleMap(int mmt, ulong moduleAddr, void* pCallback, void* token) => HResults.E_NOTIMPL;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue