Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion docs/design/datacontracts/Exception.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ record struct ExceptionData(

``` csharp
TargetPointer GetNestedExceptionInfo(TargetPointer exceptionInfoAddr, out TargetPointer nextNestedExceptionInfo);
ExceptionData GetExceptionData(TargetPointer exceptionAddr)
ExceptionData GetExceptionData(TargetPointer exceptionAddr);
```

## Version 1
Expand Down Expand Up @@ -53,4 +53,5 @@ ExceptionData GetExceptionData(TargetPointer exceptionAddr)
target.Read<int>(exceptionAddr + /* Exception::XCode offset */),
);
}

```
4 changes: 4 additions & 0 deletions docs/design/datacontracts/Object.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ TargetPointer GetMethodTableAddress(TargetPointer address)
string GetStringValue(TargetPointer address)
{
TargetPointer mt = GetMethodTableAddress(address);
if (mt == TargetPointer.Null)
throw new ArgumentException("Address represents a set-free object");
TargetPointer stringMethodTable = target.ReadPointer(target.ReadGlobalPointer("StringMethodTable"));
if (mt != stringMethodTable)
throw new ArgumentException("Address does not represent a string object", nameof(address));
Expand All @@ -70,6 +72,8 @@ string GetStringValue(TargetPointer address)
TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPointer boundsStart, out TargetPointer lowerBounds)
{
TargetPointer mt = GetMethodTableAddress(address);
if (mt == TargetPointer.Null)
throw new ArgumentException("Address represents a set-free object");
Contracts.IRuntimeTypeSystem rts = target.Contracts.RuntimeTypeSystem;
TypeHandle typeHandle = rts.GetTypeHandle(mt);
uint rank;
Expand Down
55 changes: 55 additions & 0 deletions docs/design/datacontracts/Thread.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,16 @@ The contract depends on the following globals
| `ThinLockThreadIdDispenser` | TargetPointer | Dispenser of thinlock IDs for locking objects
| `NumberOfTlsOffsetsNotUsedInNoncollectibleArray` | byte | Number of unused slots in noncollectible TLS array
| `PtrArrayOffsetToDataArray` | TargetPointer | Offset from PtrArray class address to start of enclosed data array
| `SizeOfGenericModeBlock` | uint32 | Size of GenericModeBlock struct

The contract additionally depends on these data descriptors

| Data Descriptor Name | Field | Meaning |
| --- | --- | --- |
| `Exception` | `WatsonBuckets` | Pointer to exception Watson buckets |
| `ExceptionInfo` | `PreviousNestedInfo` | Pointer to previous nested exception info |
| `ExceptionInfo` | `ThrownObjectHandle` | Pointer to exception object handle |
| `ExceptionInfo` | `ExceptionWatsonBucketTrackerBuckets` | Pointer to Watson unhandled buckets on non-Unix |
| `GCAllocContext` | `Pointer` | GC allocation pointer |
| `GCAllocContext` | `Limit` | Allocation limit pointer |
| `IdDispenser` | `HighestId` | Highest possible small thread ID |
Expand All @@ -94,6 +98,7 @@ The contract additionally depends on these data descriptors
| `Thread` | `ExceptionTracker` | Pointer to exception tracking information |
| `Thread` | `RuntimeThreadLocals` | Pointer to some thread-local storage |
| `Thread` | `ThreadLocalDataPtr` | Pointer to thread local data structure |
| `Thread` | `UEWatsonBucketTrackerBuckets` | Pointer to thread Watson buckets data |
| `ThreadLocalData` | `NonCollectibleTlsData` | Count of non-collectible TLS data entries |
| `ThreadLocalData` | `NonCollectibleTlsArrayData` | Pointer to non-collectible TLS array data |
| `ThreadLocalData` | `CollectibleTlsData` | Count of collectible TLS data entries |
Expand All @@ -105,6 +110,13 @@ The contract additionally depends on these data descriptors
| `ThreadStore` | `BackgroundCount` | Number of background threads |
| `ThreadStore` | `PendingCount` | Number of pending threads |
| `ThreadStore` | `DeadCount` | Number of dead threads |

The contract depends on the following other contracts

| Contract |
| --- |
| Object |

``` csharp
enum TLSIndexType
{
Expand All @@ -113,6 +125,7 @@ enum TLSIndexType
DirectOnThreadLocalData = 2,
};


ThreadStoreData GetThreadStoreData()
{
TargetPointer threadStore = target.ReadGlobalPointer("ThreadStore");
Expand Down Expand Up @@ -240,4 +253,46 @@ TargetPointer IThread.GetThreadLocalStaticBase(TargetPointer threadPointer, Targ
}
return threadLocalStaticBase;
}

byte[] IThread.GetWatsonBuckets(TargetPointer threadPointer)
{
TargetPointer readFrom;
TargetPointer exceptionTrackerPtr = _target.ReadPointer(threadPointer + /*Thread::ExceptionTracker offset */);
if (exceptionTrackerPtr == TargetPointer.Null)
return Array.Empty<byte>();
TargetPointer thrownObjectHandle = target.ReadPointer(exceptionTrackerPtr + /* ExceptionInfo::ThrownObjectHandle offset */);
TargetPointer throwableObjectPtr = target.ReadPointer(thrownObjectHandle);
if (throwableObjectPtr != TargetPointer.Null)
{
TargetPointer watsonBuckets = target.ReadPointer(throwableObjectPtr + /* Exception::WatsonBuckets offset */);
if (watsonBuckets != TargetPointer.Null)
{
readFrom = _target.Contracts.Object.GetArrayData(watsonBuckets, out _, out _, out _);
}
else
{
readFrom = target.ReadPointer(threadPointer + /* Thread::UEWatsonBucketTrackerBuckets offset */);
if (readFrom == TargetPointer.Null)
{
readFrom = target.ReadPointer(exceptionTrackerPtr + /* ExceptionInfo::ExceptionWatsonBucketTrackerBuckets offset */);
}
else
{
return Array.Empty<byte>();
}
}
}
else
{
readFrom = target.ReadPointer(threadPointer + /* Thread::UEWatsonBucketTrackerBuckets offset */);
}

Span<byte> span = new byte[_target.ReadGlobal<uint>("SizeOfGenericModeBlock")];
if (readFrom == TargetPointer.Null)
return Array.Empty<byte>();

_target.ReadBuffer(readFrom, span);
return span.ToArray();
}

```
1 change: 1 addition & 0 deletions docs/design/datacontracts/debug_interface_globals.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,4 @@ Global variables used
| MaxClrNotificationArgs | uint32 | Identify the maximum number of CLR notification arguments |
| ClrNotificationArguments | TargetPointer | Identify where the ClrNotificationArguments exists |
| DefaultADID | uint | Identify the default AppDomain ID |
| SizeOfGenericModeBlock | uint | Size of the GenericModeBlock struct |
9 changes: 8 additions & 1 deletion src/coreclr/vm/datadescriptor/datadescriptor.inc
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ CDAC_TYPE_FIELD(Thread, pointer, LinkNext, cdac_data<Thread>::Link)
CDAC_TYPE_FIELD(Thread, /*pointer*/, ThreadLocalDataPtr, cdac_data<Thread>::ThreadLocalDataPtr)
#ifndef TARGET_UNIX
CDAC_TYPE_FIELD(Thread, /*pointer*/, TEB, cdac_data<Thread>::TEB)
CDAC_TYPE_FIELD(Thread, /*pointer*/, UEWatsonBucketTrackerBuckets, cdac_data<Thread>::UEWatsonBucketTrackerBuckets)
#endif
CDAC_TYPE_END(Thread)

Expand Down Expand Up @@ -104,8 +105,11 @@ CDAC_TYPE_END(Exception)

CDAC_TYPE_BEGIN(ExceptionInfo)
CDAC_TYPE_INDETERMINATE(ExceptionInfo)
CDAC_TYPE_FIELD(ExceptionInfo, /*pointer*/, ThrownObject, offsetof(ExInfo, m_hThrowable))
CDAC_TYPE_FIELD(ExceptionInfo, /*pointer*/, ThrownObjectHandle, offsetof(ExInfo, m_hThrowable))
CDAC_TYPE_FIELD(PreviousNestedInfo, /*pointer*/, PreviousNestedInfo, offsetof(ExInfo, m_pPrevNestedInfo))
#ifndef TARGET_UNIX
CDAC_TYPE_FIELD(ExceptionWatsonBucketTrackerBuckets, /*pointer*/, ExceptionWatsonBucketTrackerBuckets, cdac_data<ExInfo>::ExceptionWatsonBucketTrackerBuckets)
#endif // TARGET_UNIX
CDAC_TYPE_END(ExceptionInfo)


Expand Down Expand Up @@ -969,6 +973,9 @@ CDAC_GLOBAL(ObjectHeaderSize, uint64, OBJHEADER_SIZE)
CDAC_GLOBAL(SyncBlockValueToObjectOffset, uint16, OBJHEADER_SIZE - cdac_data<ObjHeader>::SyncBlockValue)
CDAC_GLOBAL(StubCodeBlockLast, uint8, STUB_CODE_BLOCK_LAST)
CDAC_GLOBAL(DefaultADID, uint32, DefaultADID)
#ifndef TARGET_UNIX
CDAC_GLOBAL(SizeOfGenericModeBlock, uint32, sizeof(GenericModeBlock))
#endif
CDAC_GLOBAL(StaticsPointerMask, uintptr_t, DynamicStaticsInfo::STATICSPOINTERMASK)
CDAC_GLOBAL(PtrArrayOffsetToDataArray, uintptr_t, offsetof(PtrArray, m_Array))
CDAC_GLOBAL(NumberOfTlsOffsetsNotUsedInNoncollectibleArray, uint8, NUMBER_OF_TLSOFFSETS_NOT_USED_IN_NONCOLLECTIBLE_ARRAY)
Expand Down
10 changes: 10 additions & 0 deletions src/coreclr/vm/exinfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ struct LastReportedFuncletInfo

struct ExInfo
{
friend struct ::cdac_data<ExInfo>;
struct DAC_EXCEPTION_POINTERS
{
PTR_EXCEPTION_RECORD ExceptionRecord;
Expand Down Expand Up @@ -510,5 +511,14 @@ struct ExInfo
static StackWalkAction RareFindParentStackFrameCallback(CrawlFrame* pCF, LPVOID pData);
};

#ifndef TARGET_UNIX
template<>
struct cdac_data<ExInfo>
{
static constexpr size_t ExceptionWatsonBucketTrackerBuckets = offsetof(ExInfo, m_WatsonBucketTracker)
+ offsetof(EHWatsonBucketTracker, m_WatsonUnhandledInfo.m_pUnhandledBuckets);
};
#endif // TARGET_UNIX

#endif // !FEATURE_EH_FUNCLETS
#endif // __ExInfo_h__
6 changes: 5 additions & 1 deletion src/coreclr/vm/exstatecommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
#define __ExStateCommon_h__

#include "stackframe.h"
#include "cdacdata.h"

class ExceptionFlags;

struct ExInfo;
#ifdef DEBUGGING_SUPPORTED
//---------------------------------------------------------------------------------------
//
Expand Down Expand Up @@ -431,6 +432,9 @@ class TypeOfReportedError
typedef DPTR(class EHWatsonBucketTracker) PTR_EHWatsonBucketTracker;
class EHWatsonBucketTracker
{
friend struct ::cdac_data<ExInfo>;
friend struct ::cdac_data<Thread>;

private:
struct
{
Expand Down
3 changes: 2 additions & 1 deletion src/coreclr/vm/threads.h
Original file line number Diff line number Diff line change
Expand Up @@ -3955,9 +3955,10 @@ struct cdac_data<Thread>
#else
static constexpr size_t ExceptionTracker = offsetof(Thread, m_ExceptionState) + offsetof(ThreadExceptionState, m_currentExInfo);
#endif

#ifndef TARGET_UNIX
static constexpr size_t TEB = offsetof(Thread, m_pTEB);
static constexpr size_t UEWatsonBucketTrackerBuckets = offsetof(Thread, m_ExceptionState) + offsetof(ThreadExceptionState, m_UEWatsonBucketTracker)
+ offsetof(EHWatsonBucketTracker, m_WatsonUnhandledInfo.m_pUnhandledBuckets);
#endif
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ public interface IThread : IContract
ThreadData GetThreadData(TargetPointer thread) => throw new NotImplementedException();
TargetPointer IdToThread(uint id) => throw new NotImplementedException();
TargetPointer GetThreadLocalStaticBase(TargetPointer threadPointer, TargetPointer tlsIndexPtr) => throw new NotImplementedException();
TargetPointer GetThrowableObject(TargetPointer threadPointer) => throw new NotImplementedException();
byte[] GetWatsonBuckets(TargetPointer threadPointer) => throw new NotImplementedException();
}

public readonly struct Thread : IThread
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public static class Globals
public const string SyncTableEntries = nameof(SyncTableEntries);

public const string ArrayBoundsZero = nameof(ArrayBoundsZero);
public const string SizeOfGenericModeBlock = nameof(SizeOfGenericModeBlock);

public const string MethodDescTokenRemainderBitCount = nameof(MethodDescTokenRemainderBitCount);
public const string DirectorySeparator = nameof(DirectorySeparator);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ TargetPointer IException.GetNestedExceptionInfo(TargetPointer exceptionInfoAddr,
{
Data.ExceptionInfo exceptionInfo = _target.ProcessedData.GetOrAdd<Data.ExceptionInfo>(exceptionInfoAddr);
nextNestedExceptionInfo = exceptionInfo.PreviousNestedInfo;
return exceptionInfo.ThrownObject.Object;
Data.ObjectHandle throwableObject = _target.ProcessedData.GetOrAdd<Data.ObjectHandle>(exceptionInfo.ThrownObjectHandle);
return throwableObject.Object;
}

ExceptionData IException.GetExceptionData(TargetPointer exceptionAddr)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ public TargetPointer GetMethodTableAddress(TargetPointer address)
string IObject.GetStringValue(TargetPointer address)
{
TargetPointer mt = GetMethodTableAddress(address);
if (mt == TargetPointer.Null)
throw new ArgumentException("Address represents a set-free object");
if (mt != _stringMethodTable)
throw new ArgumentException("Address does not represent a string object", nameof(address));

Expand All @@ -63,6 +65,8 @@ string IObject.GetStringValue(TargetPointer address)
public TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPointer boundsStart, out TargetPointer lowerBounds)
{
TargetPointer mt = GetMethodTableAddress(address);
if (mt == TargetPointer.Null)
throw new ArgumentException("Address represents a set-free object");
Contracts.IRuntimeTypeSystem typeSystemContract = _target.Contracts.RuntimeTypeSystem;
TypeHandle typeHandle = typeSystemContract.GetTypeHandle(mt);
uint rank;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,4 +154,46 @@ TargetPointer IThread.GetThreadLocalStaticBase(TargetPointer threadPointer, Targ
}
return threadLocalStaticBase;
}

byte[] IThread.GetWatsonBuckets(TargetPointer threadPointer)
{
TargetPointer readFrom;
Data.Thread thread = _target.ProcessedData.GetOrAdd<Data.Thread>(threadPointer);
TargetPointer ExceptionTrackerPtr = _target.ReadPointer(thread.ExceptionTracker);
if (ExceptionTrackerPtr == TargetPointer.Null)
return Array.Empty<byte>();
Data.ExceptionInfo exceptionTracker = _target.ProcessedData.GetOrAdd<Data.ExceptionInfo>(ExceptionTrackerPtr);
Data.ObjectHandle throwableObject = _target.ProcessedData.GetOrAdd<Data.ObjectHandle>(exceptionTracker.ThrownObjectHandle);
if (throwableObject.Object != TargetPointer.Null)
{
Data.Exception exception = _target.ProcessedData.GetOrAdd<Data.Exception>(throwableObject.Object);
if (exception.WatsonBuckets != TargetPointer.Null)
{
readFrom = _target.Contracts.Object.GetArrayData(exception.WatsonBuckets, out _, out _, out _);
}
else
{
readFrom = thread.UEWatsonBucketTrackerBuckets;
if (readFrom == TargetPointer.Null)
{
readFrom = exceptionTracker.ExceptionWatsonBucketTrackerBuckets;
}
else
{
return Array.Empty<byte>();
}
}
}
else
{
readFrom = thread.UEWatsonBucketTrackerBuckets;
}

if (readFrom == TargetPointer.Null)
return Array.Empty<byte>();

byte[] rval = new byte[_target.ReadGlobal<uint>(Constants.Globals.SizeOfGenericModeBlock)];
_target.ReadBuffer(readFrom, rval);
return rval;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ public ExceptionInfo(Target target, TargetPointer address)
Target.TypeInfo type = target.GetTypeInfo(DataType.ExceptionInfo);

PreviousNestedInfo = target.ReadPointer(address + (ulong)type.Fields[nameof(PreviousNestedInfo)].Offset);
ThrownObject = target.ProcessedData.GetOrAdd<ObjectHandle>(
target.ReadPointer(address + (ulong)type.Fields[nameof(ThrownObject)].Offset));
ThrownObjectHandle = target.ReadPointer(address + (ulong)type.Fields[nameof(ThrownObjectHandle)].Offset);
if (type.Fields.ContainsKey(nameof(ExceptionWatsonBucketTrackerBuckets)))
ExceptionWatsonBucketTrackerBuckets = target.ReadPointer(address + (ulong)type.Fields[nameof(ExceptionWatsonBucketTrackerBuckets)].Offset);
}

public TargetPointer PreviousNestedInfo { get; init; }
public ObjectHandle ThrownObject { get; init; }
public TargetPointer ThrownObjectHandle { get; init; }
public TargetPointer ExceptionWatsonBucketTrackerBuckets { get; init; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// 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 Object : IData<Object>
{
static Object IData<Object>.Create(Target target, TargetPointer address) => new Object(target, address);
public Object(Target target, TargetPointer address)
{
Target.TypeInfo type = target.GetTypeInfo(DataType.Object);

MethodTable = target.ProcessedData.GetOrAdd<Data.MethodTable>(target.ReadPointer(address + (ulong)type.Fields["m_pMethTab"].Offset));
}

public MethodTable MethodTable { get; init; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public Thread(Target target, TargetPointer address)

// Address of the exception tracker
ExceptionTracker = address + (ulong)type.Fields[nameof(ExceptionTracker)].Offset;
UEWatsonBucketTrackerBuckets = target.ReadPointer(address + (ulong)type.Fields[nameof(UEWatsonBucketTrackerBuckets)].Offset);
ThreadLocalDataPtr = target.ReadPointer(address + (ulong)type.Fields[nameof(ThreadLocalDataPtr)].Offset);
}

Expand All @@ -46,5 +47,6 @@ public Thread(Target target, TargetPointer address)
public ObjectHandle LastThrownObject { get; init; }
public TargetPointer LinkNext { get; init; }
public TargetPointer ExceptionTracker { get; init; }
public TargetPointer UEWatsonBucketTrackerBuckets { get; init; }
public TargetPointer ThreadLocalDataPtr { get; init; }
}
Loading
Loading