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
25 changes: 5 additions & 20 deletions src/coreclr/debug/daccess/dacdbiimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6767,11 +6767,11 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::IsValidObject(CORDB_ADDRESS obj,
return hr;
}

HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CreateRefWalk(OUT RefWalkHandle * pHandle, BOOL walkStacks, BOOL walkFQ, UINT32 handleWalkMask)
HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::CreateRefWalk(OUT RefWalkHandle * pHandle, BOOL walkStacks, UINT32 handleWalkMask)
{
DD_ENTER_MAY_THROW;

DacRefWalker *walker = new (nothrow) DacRefWalker(this, walkStacks, walkFQ, handleWalkMask, TRUE);
DacRefWalker *walker = new (nothrow) DacRefWalker(this, walkStacks, handleWalkMask, TRUE);

if (walker == NULL)
return E_OUTOFMEMORY;
Expand Down Expand Up @@ -7410,9 +7410,9 @@ HRESULT STDMETHODCALLTYPE DacDbiInterfaceImpl::GetGenericArgTokenIndex(VMPTR_Met
return S_OK;
}

DacRefWalker::DacRefWalker(ClrDataAccess *dac, BOOL walkStacks, BOOL walkFQ, UINT32 handleMask, BOOL resolvePointers)
: mDac(dac), mWalkStacks(walkStacks), mWalkFQ(walkFQ), mHandleMask(handleMask), mStackWalker(NULL),
mResolvePointers(resolvePointers), mHandleWalker(NULL), mFQStart(PTR_NULL), mFQEnd(PTR_NULL), mFQCurr(PTR_NULL)
DacRefWalker::DacRefWalker(ClrDataAccess *dac, BOOL walkStacks, UINT32 handleMask, BOOL resolvePointers)
: mDac(dac), mWalkStacks(walkStacks), mHandleMask(handleMask), mStackWalker(NULL),
mResolvePointers(resolvePointers), mHandleWalker(NULL)
{
Comment thread
rcj1 marked this conversation as resolved.
}

Expand Down Expand Up @@ -7507,21 +7507,6 @@ HRESULT DacRefWalker::Next(ULONG celt, DacGcReference roots[], ULONG *pceltFetch
}
}

if (total < celt)
{
while (total < celt && mFQCurr < mFQEnd)
{
DacGcReference &ref = roots[total++];

ref.vmDomain = VMPTR_AppDomain::NullPtr();
ref.objHnd.SetDacTargetPtr(mFQCurr.GetAddr());
ref.dwType = (DWORD)CorReferenceFinalizer;
ref.i64ExtraData = 0;

mFQCurr++;
}
}

while (total < celt && mStackWalker)
{
ULONG fetched = 0;
Expand Down
11 changes: 3 additions & 8 deletions src/coreclr/debug/daccess/dacdbiimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ class DacDbiInterfaceImpl :

HRESULT STDMETHODCALLTYPE IsValidObject(CORDB_ADDRESS obj, OUT BOOL * pResult);

HRESULT STDMETHODCALLTYPE CreateRefWalk(RefWalkHandle * pHandle, BOOL walkStacks, BOOL walkFQ, UINT32 handleWalkMask);
HRESULT STDMETHODCALLTYPE CreateRefWalk(RefWalkHandle * pHandle, BOOL walkStacks, UINT32 handleWalkMask);
HRESULT STDMETHODCALLTYPE DeleteRefWalk(RefWalkHandle handle);
HRESULT STDMETHODCALLTYPE WalkRefs(RefWalkHandle handle, ULONG count, OUT DacGcReference * objects, OUT ULONG *pFetched);

Expand Down Expand Up @@ -958,7 +958,7 @@ class DDHolder
class DacRefWalker
{
public:
DacRefWalker(ClrDataAccess *dac, BOOL walkStacks, BOOL walkFQ, UINT32 handleMask, BOOL resolvePointers);
DacRefWalker(ClrDataAccess *dac, BOOL walkStacks, UINT32 handleMask, BOOL resolvePointers);
~DacRefWalker();

HRESULT Init();
Expand All @@ -971,7 +971,7 @@ class DacRefWalker

private:
ClrDataAccess *mDac;
BOOL mWalkStacks, mWalkFQ;
BOOL mWalkStacks;
UINT32 mHandleMask;

// Stacks
Expand All @@ -980,11 +980,6 @@ class DacRefWalker

// Handles
DacHandleWalker *mHandleWalker;

// FQ
PTR_PTR_Object mFQStart;
PTR_PTR_Object mFQEnd;
PTR_PTR_Object mFQCurr;
};

#endif // _DACDBI_IMPL_H_
6 changes: 3 additions & 3 deletions src/coreclr/debug/di/process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2554,13 +2554,13 @@ HRESULT CordbProcess::GetTypeForObject(CORDB_ADDRESS addr, CordbType **ppType, C
// CordbRefEnum
// ******************************************
CordbRefEnum::CordbRefEnum(CordbProcess *proc, BOOL walkWeakRefs)
: CordbBase(proc, 0, enumCordbHeap), mRefHandle(0), mEnumStacksFQ(TRUE),
: CordbBase(proc, 0, enumCordbHeap), mRefHandle(0), mEnumStacks(TRUE),
mHandleMask((UINT32)(walkWeakRefs ? CorHandleAll : CorHandleStrongOnly))
{
}

CordbRefEnum::CordbRefEnum(CordbProcess *proc, CorGCReferenceType types)
: CordbBase(proc, 0, enumCordbHeap), mRefHandle(0), mEnumStacksFQ(FALSE),
: CordbBase(proc, 0, enumCordbHeap), mRefHandle(0), mEnumStacks(FALSE),
mHandleMask((UINT32)types)
{
}
Expand Down Expand Up @@ -2659,7 +2659,7 @@ HRESULT CordbRefEnum::Next(ULONG celt, COR_GC_REFERENCE refs[], ULONG *pceltFetc
EX_TRY
{
if (!mRefHandle)
hr = process->GetDAC()->CreateRefWalk(&mRefHandle, mEnumStacksFQ, mEnumStacksFQ, mHandleMask);
hr = process->GetDAC()->CreateRefWalk(&mRefHandle, mEnumStacks, mHandleMask);

if (SUCCEEDED(hr))
{
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/debug/di/rspriv.h
Original file line number Diff line number Diff line change
Expand Up @@ -10613,7 +10613,7 @@ class CordbRefEnum : public CordbBase, public ICorDebugGCReferenceEnum

private:
RefWalkHandle mRefHandle;
BOOL mEnumStacksFQ;
BOOL mEnumStacks;
UINT32 mHandleMask;
};

Expand Down
3 changes: 1 addition & 2 deletions src/coreclr/debug/inc/dacdbiinterface.h
Original file line number Diff line number Diff line change
Expand Up @@ -1980,13 +1980,12 @@ IDacDbiInterface : public IUnknown
// Parameters:
// pHandle - out - the reference walk handle to create
// walkStacks - in - whether or not to report stack references
// walkFQ - in - whether or not to report references from the finalizer queue
// handleWalkMask - in - the types of handles report (see CorGCReferenceType, cordebug.idl)
// Returns:
// An HRESULT indicating whether it succeeded or failed.
// Exceptions:
// Returns an HRESULT indicating success or failure.
virtual HRESULT STDMETHODCALLTYPE CreateRefWalk(OUT RefWalkHandle * pHandle, BOOL walkStacks, BOOL walkFQ, UINT32 handleWalkMask) = 0;
virtual HRESULT STDMETHODCALLTYPE CreateRefWalk(OUT RefWalkHandle * pHandle, BOOL walkStacks, UINT32 handleWalkMask) = 0;

// Deletes a reference walk.
// Parameters:
Expand Down
2 changes: 1 addition & 1 deletion src/coreclr/inc/dacdbi.idl
Original file line number Diff line number Diff line change
Expand Up @@ -384,7 +384,7 @@ interface IDacDbiInterface : IUnknown
HRESULT IsValidObject([in] CORDB_ADDRESS obj, [out] BOOL * pResult);

// Reference Walking
HRESULT CreateRefWalk([out] RefWalkHandle * pHandle, [in] BOOL walkStacks, [in] BOOL walkFQ, [in] UINT32 handleWalkMask);
HRESULT CreateRefWalk([out] RefWalkHandle * pHandle, [in] BOOL walkStacks, [in] UINT32 handleWalkMask);
HRESULT DeleteRefWalk([in] RefWalkHandle handle);
HRESULT WalkRefs([in] RefWalkHandle handle, [in] ULONG count, [out] struct DacGcReference * refs, [out] ULONG * pFetched);
Comment thread
rcj1 marked this conversation as resolved.

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Linq;

namespace Microsoft.Diagnostics.DataContractReader.Contracts.Extensions;

public static class IGCExtensions
{
public static IEnumerable<(GCHeapSegmentInfo Segment, GCHeapData Heap)> EnumerateAllSegments(this IGC gc)
{
string[] gcIdentifiers = gc.GetGCIdentifiers();
bool isWorkstation = gcIdentifiers.Contains(GCIdentifiers.Workstation);
Comment thread
rcj1 marked this conversation as resolved.
foreach (GCHeapData heap in EnumerateHeaps(gc, isWorkstation))
Comment thread
rcj1 marked this conversation as resolved.
{
foreach (GCHeapSegmentInfo seg in gc.EnumerateHeapSegments(heap))
{
yield return (seg, heap);
}
}
}

private static IEnumerable<GCHeapData> EnumerateHeaps(IGC gc, bool isWorkstation)
{
if (isWorkstation)
{
yield return gc.GetHeapData();
}
else
{
foreach (TargetPointer heapAddress in gc.GetGCHeaps())
yield return gc.GetHeapData(heapAddress);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public enum StackSourceType
public class StackReferenceData
{
public bool HasRegisterInformation { get; init; }
public bool IsInteriorPointer { get; init; }
public int Register { get; init; }
Comment thread
max-charlamb marked this conversation as resolved.
public int Offset { get; init; }
public TargetPointer Address { get; init; }
Expand Down Expand Up @@ -91,7 +92,7 @@ public interface IStackWalk : IContract
static string IContract.Name => nameof(StackWalk);
IEnumerable<IStackDataFrameHandle> CreateStackWalk(ThreadData threadData) => throw new NotImplementedException();
IEnumerable<IStackDataFrameHandle> CreateStackWalk(ThreadData threadData, byte[] contextBuffer, bool isFirst = true) => throw new NotImplementedException();
IReadOnlyList<StackReferenceData> WalkStackReferences(ThreadData threadData) => throw new NotImplementedException();
IReadOnlyList<StackReferenceData> WalkStackReferences(ThreadData threadData, bool resolveInteriorPointers) => throw new NotImplementedException();
byte[] GetRawContext(IStackDataFrameHandle stackDataFrameHandle, StackwalkFlag flags = StackwalkFlag.Default) => throw new NotImplementedException();
Comment thread
rcj1 marked this conversation as resolved.
TargetPointer GetFrameAddress(IStackDataFrameHandle stackDataFrameHandle) => throw new NotImplementedException();
string GetFrameName(TargetPointer frameIdentifier) => throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,22 @@

using System;
using System.Collections.Generic;
using Microsoft.Diagnostics.DataContractReader.Contracts.Extensions;

namespace Microsoft.Diagnostics.DataContractReader.Contracts.StackWalkHelpers;
Comment thread
rcj1 marked this conversation as resolved.

internal class GcScanContext
{

private readonly Target _target;
private readonly IGC _gc;
Comment thread
rcj1 marked this conversation as resolved.
private readonly IRuntimeTypeSystem _rts;

private readonly LinearReadCache _cache;
private readonly uint _numComponentsOffsetArray;
private readonly uint _numComponentsOffsetString;
private readonly ulong _methodTableOffset;
private readonly byte _objectToMethodTableUnmask;
public bool ResolveInteriorPointers { get; }
public List<StackRefData> StackRefs { get; } = [];
public TargetPointer StackPointer { get; private set; }
Expand All @@ -25,6 +34,13 @@ public GcScanContext(Target target, bool resolveInteriorPointers)
{
_target = target;
ResolveInteriorPointers = resolveInteriorPointers;
_gc = target.Contracts.GC;
Comment thread
rcj1 marked this conversation as resolved.
_rts = target.Contracts.RuntimeTypeSystem;
_cache = new LinearReadCache(target);
_numComponentsOffsetArray = (uint)target.GetTypeInfo(DataType.Array).Fields[Constants.FieldNames.Array.NumComponents].Offset;
_numComponentsOffsetString = (uint)target.GetTypeInfo(DataType.String).Fields["m_StringLength"].Offset;
_methodTableOffset = (ulong)target.GetTypeInfo(DataType.Object).Fields["m_pMethTab"].Offset;
_objectToMethodTableUnmask = target.ReadGlobal<byte>(Constants.Globals.ObjectToMethodTableUnmask);
}
Comment thread
rcj1 marked this conversation as resolved.

public void UpdateScanContext(TargetPointer sp, TargetPointer ip, TargetPointer frame, StackRefData.SourceTypes? sourceTypeOverride = null)
Expand Down Expand Up @@ -59,6 +75,7 @@ public void RecordDeferredFrame(TargetPointer frameAddress)
StackRefs.Add(new StackRefData
{
HasRegisterInformation = false,
IsInteriorPointer = false,
Register = 0,
Offset = 0,
Address = 0,
Expand Down Expand Up @@ -88,14 +105,16 @@ public void GCEnumCallback(TargetPointer pObject, GcScanFlags flags, GcScanSlotL

if (flags.HasFlag(GcScanFlags.GC_CALL_INTERIOR) && ResolveInteriorPointers)
{
// TODO(stackref): handle interior pointers
// https://github.com/dotnet/runtime/issues/125728
throw new NotImplementedException();
TargetPointer interiorObj = GetInteriorPointer(obj);
if (interiorObj == TargetPointer.Null)
return;
obj = interiorObj;
}
Comment thread
rcj1 marked this conversation as resolved.
Comment thread
rcj1 marked this conversation as resolved.
Comment thread
rcj1 marked this conversation as resolved.

StackRefData data = new()
{
HasRegisterInformation = true,
IsInteriorPointer = flags.HasFlag(GcScanFlags.GC_CALL_INTERIOR),
Register = loc.Reg,
Offset = loc.RegOffset,
Address = addr,
Expand All @@ -109,21 +128,90 @@ public void GCEnumCallback(TargetPointer pObject, GcScanFlags flags, GcScanSlotL
StackRefs.Add(data);
}

public void GCReportCallback(TargetPointer ppObj, GcScanFlags flags)
private TargetPointer GetInteriorPointer(TargetPointer obj)
{
if (flags.HasFlag(GcScanFlags.GC_CALL_INTERIOR) && ResolveInteriorPointers)
TargetPointer outerObj = TargetPointer.Null;
foreach ((GCHeapSegmentInfo seg, GCHeapData _) in _gc.EnumerateAllSegments())
Comment thread
rcj1 marked this conversation as resolved.
{
// TODO(stackref): handle interior pointers
// https://github.com/dotnet/runtime/issues/125728
throw new NotImplementedException();
if (obj.Value < seg.Start.Value || obj.Value >= seg.End.Value)
continue;

TargetPointer currentObj = _gc.GetPotentialNextObjectAddress(seg.Start, 0, seg);
ulong size = 0;
while (currentObj.Value <= obj.Value)
{
Comment thread
rcj1 marked this conversation as resolved.
// Replicate IObject.GetMethodTableAddress in fast path with linear read cache
if (!_cache.TryReadPointer(currentObj.Value + _methodTableOffset, out TargetPointer mt))
Comment thread
rcj1 marked this conversation as resolved.
{
return TargetPointer.Null;
}
mt = mt.Value & (ulong)~_objectToMethodTableUnmask;

// Replicate IObject.GetSize in fast path with linear read cache
if (!TryGetObjectSize(currentObj, mt, out size) || size == 0)
{
return TargetPointer.Null;
}

size = _gc.AlignObjectSize(size, seg.Generation);
if (currentObj.Value + size > seg.End.Value || size == 0)
{
return TargetPointer.Null;
}
outerObj = currentObj;
Comment thread
rcj1 marked this conversation as resolved.
currentObj = _gc.GetPotentialNextObjectAddress(currentObj, size, seg);
}
return outerObj + size > obj ? outerObj : TargetPointer.Null;
}
return outerObj;
}

private bool TryGetObjectSize(TargetPointer objAddr, TargetPointer mt, out ulong size)
Comment thread
rcj1 marked this conversation as resolved.
{
size = 0;
try
{
TypeHandle handle = _rts.GetTypeHandle(mt);
ulong baseSize = _rts.GetBaseSize(handle);
uint componentSize = _rts.GetComponentSize(handle);
uint numComponentsOffset = 0;
if (componentSize != 0)
{
if (_rts.IsArray(handle, out _) || _rts.IsFreeObjectMethodTable(handle))
numComponentsOffset = _numComponentsOffsetArray;
else if (_rts.IsString(handle))
numComponentsOffset = _numComponentsOffsetString;
else
return false; // unrecognized component type
if (!_cache.TryReadUInt32(objAddr.Value + numComponentsOffset, out uint numComponents))
return false;
baseSize += (ulong)componentSize * numComponents;
}
size = baseSize;
return true;
}
catch
{
// The MT may be corrupt — surface as a read failure.
return false;
}
}

public void GCReportCallback(TargetPointer ppObj, GcScanFlags flags)
{
// Read the object pointer from the stack slot.
TargetPointer obj = _target.ReadPointer(ppObj);
if (flags.HasFlag(GcScanFlags.GC_CALL_INTERIOR) && ResolveInteriorPointers)
{
TargetPointer interiorObj = GetInteriorPointer(obj);
if (interiorObj != TargetPointer.Null)
obj = interiorObj;
}

StackRefData data = new()
{
HasRegisterInformation = false,
IsInteriorPointer = flags.HasFlag(GcScanFlags.GC_CALL_INTERIOR),
Register = 0,
Offset = 0,
Address = ppObj,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ public enum SourceTypes
}

public bool HasRegisterInformation { get; set; }
public bool IsInteriorPointer { get; set; }
public int Register { get; set; }
public int Offset { get; set; }
public TargetPointer Address { get; set; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ private IEnumerable<IStackDataFrameHandle> RunStackWalk(
}
}

IReadOnlyList<StackReferenceData> IStackWalk.WalkStackReferences(ThreadData threadData)
IReadOnlyList<StackReferenceData> IStackWalk.WalkStackReferences(ThreadData threadData, bool resolveInteriorPointers)
{
// Initialize the walk data directly
IPlatformAgnosticContext context = IPlatformAgnosticContext.GetContextForPlatform(_target);
Expand All @@ -273,7 +273,7 @@ IReadOnlyList<StackReferenceData> IStackWalk.WalkStackReferences(ThreadData thre
if (walkData.State == StackWalkState.Frameless && CheckForSkippedFrames(walkData))
walkData.State = StackWalkState.SkippedFrame;

GcScanContext scanContext = new(_target, resolveInteriorPointers: false);
GcScanContext scanContext = new(_target, resolveInteriorPointers);

// Filter drives Next() directly, matching native Filter()+NextRaw() integration.
// This prevents funclet-to-parent transitions from re-visiting already-walked frames.
Expand Down Expand Up @@ -361,6 +361,7 @@ IReadOnlyList<StackReferenceData> IStackWalk.WalkStackReferences(ThreadData thre
return scanContext.StackRefs.Select(r => new StackReferenceData
{
HasRegisterInformation = r.HasRegisterInformation,
IsInteriorPointer = r.IsInteriorPointer,
Register = r.Register,
Offset = r.Offset,
Address = r.Address,
Expand Down
Loading
Loading