Skip to content

Commit

Permalink
Update to newer ClrMD which might reduce build crashes
Browse files Browse the repository at this point in the history
  • Loading branch information
ashmind committed Jun 2, 2024
1 parent 6ff1cda commit 39d93b5
Show file tree
Hide file tree
Showing 33 changed files with 682 additions and 853 deletions.
2 changes: 1 addition & 1 deletion source/Container/Container.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

<ItemGroup>
<PackageReference Include="FSharp.Core" Version="6.0.1" />
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="2.0.226801" />
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="3.1.512801" />
<PackageReference Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.10.13" />
<PackageReference Include="protobuf-net" Version="3.0.101" />
<PackageReference Include="protobuf-net.BuildTools" Version="3.0.81" PrivateAssets="all" IncludeAssets="runtime;build;native;contentfiles;analyzers;buildtransitive" />
Expand Down
206 changes: 103 additions & 103 deletions source/Container/Runtime/MemoryBytesInspector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,133 +4,133 @@
using Microsoft.Diagnostics.Runtime;
using SharpLab.Runtime.Internal;

namespace SharpLab.Container.Runtime {
internal class MemoryBytesInspector : IMemoryBytesInspector {
private readonly Pool<ClrRuntime> _runtimePool;
namespace SharpLab.Container.Runtime;

public MemoryBytesInspector(Pool<ClrRuntime> runtimePool) {
_runtimePool = runtimePool;
}
internal class MemoryBytesInspector : IMemoryBytesInspector {
private readonly Pool<ClrRuntime> _runtimePool;

public MemoryInspection InspectHeap(object @object) {
if (@object == null)
throw new ArgumentNullException(nameof(@object), $"Inspect.Heap can't inspect null, as it does not point to a valid location on the heap.");
public MemoryBytesInspector(Pool<ClrRuntime> runtimePool) {
_runtimePool = runtimePool;
}

using var runtimeLease = _runtimePool.GetOrCreate();
var runtime = runtimeLease.Object;
runtime.FlushCachedData();
public MemoryInspection InspectHeap(object @object) {
if (@object == null)
throw new ArgumentNullException(nameof(@object), $"Inspect.Heap can't inspect null, as it does not point to a valid location on the heap.");

var address = (ulong)GetHeapPointer(@object);
var objectType = runtime.Heap.GetObjectType(address);
if (objectType == null)
throw new ClrInformationNotFoundException($"Failed to find object type for address 0x{address:X}.");
using var runtimeLease = _runtimePool.GetOrCreate();
var runtime = runtimeLease.Object;
runtime.FlushCachedData();

var objectSize = runtime.Heap.GetObjectSize(address, objectType);
var address = (ulong)GetHeapPointer(@object);
var objectType = runtime.Heap.GetObjectType(address);
if (objectType == null)
throw new ClrInformationNotFoundException($"Failed to find object type for address 0x{address:X}.");

// Move by one pointer size back -- Object Header,
// see https://blogs.msdn.microsoft.com/seteplia/2017/05/26/managed-object-internals-part-1-layout/
//
// Not sure if there is a better way to get this through ClrMD yet.
// https://github.com/Microsoft/clrmd/issues/99
var objectStart = address - (uint)IntPtr.Size;
var data = ReadMemory(runtime, objectStart, objectSize);
var objectSize = runtime.Heap.GetObject(address, objectType).Size;

var labels = CreateLabelsFromType(objectType, address, objectStart, first: (index: 2, offset: 2 * IntPtr.Size));
labels[0] = new MemoryInspectionLabel("header", 0, IntPtr.Size);
labels[1] = new MemoryInspectionLabel("type handle", IntPtr.Size, IntPtr.Size);
// Move by one pointer size back -- Object Header,
// see https://blogs.msdn.microsoft.com/seteplia/2017/05/26/managed-object-internals-part-1-layout/
//
// Not sure if there is a better way to get this through ClrMD yet.
// https://github.com/Microsoft/clrmd/issues/99
var objectStart = address - (uint)IntPtr.Size;
var data = ReadMemory(runtime, objectStart, objectSize);

return new MemoryInspection($"{objectType.Name} at 0x{address:X}", labels, data);
}
var labels = CreateLabelsFromType(objectType, address, objectStart, first: (index: 2, offset: 2 * IntPtr.Size));
labels[0] = new MemoryInspectionLabel("header", 0, IntPtr.Size);
labels[1] = new MemoryInspectionLabel("type handle", IntPtr.Size, IntPtr.Size);

public unsafe MemoryInspection InspectStack<T>(in T value) {
using var runtimeLease = _runtimePool.GetOrCreate();
var runtime = runtimeLease.Object;
return new MemoryInspection($"{objectType.Name} at 0x{address:X}", labels, data);
}

var type = typeof(T);
public unsafe MemoryInspection InspectStack<T>(in T value) {
using var runtimeLease = _runtimePool.GetOrCreate();
var runtime = runtimeLease.Object;

var address = (ulong)Unsafe.AsPointer(ref Unsafe.AsRef(in value));
var size = type.IsValueType ? (ulong)Unsafe.SizeOf<T>() : (uint)IntPtr.Size;
var data = ReadMemory(runtime, address, size);
var type = typeof(T);

MemoryInspectionLabel[] labels;
if (type.IsValueType && !type.IsPrimitive) {
runtime.FlushCachedData();
var methodTableAddress = (ulong)type.TypeHandle.Value;
var runtimeType = runtime.GetTypeByMethodTable(methodTableAddress)
?? throw new ClrInformationNotFoundException($"Could not find type by method table at 0x{methodTableAddress:X}");
labels = CreateLabelsFromType(runtimeType, address, address + (uint)IntPtr.Size);
}
else {
labels = Array.Empty<MemoryInspectionLabel>();
}

var title = type.IsValueType
? $"{type.FullName}"
: $"Pointer to {type.FullName}";
var address = (ulong)Unsafe.AsPointer(ref Unsafe.AsRef(in value));
var size = type.IsValueType ? (ulong)Unsafe.SizeOf<T>() : (uint)IntPtr.Size;
var data = ReadMemory(runtime, address, size);

return new MemoryInspection(title, labels, data);
MemoryInspectionLabel[] labels;
if (type.IsValueType && !type.IsPrimitive) {
runtime.FlushCachedData();
var methodTableAddress = (ulong)type.TypeHandle.Value;
var runtimeType = runtime.GetTypeByMethodTable(methodTableAddress)
?? throw new ClrInformationNotFoundException($"Could not find type by method table at 0x{methodTableAddress:X}");
labels = CreateLabelsFromType(runtimeType, address, address + (uint)IntPtr.Size);
}

private static byte[] ReadMemory(ClrRuntime runtime, ulong address, ulong size) {
var data = new byte[size];
runtime.DataTarget!.DataReader.Read(address, data);
return data;
else {
labels = Array.Empty<MemoryInspectionLabel>();
}

private MemoryInspectionLabel[] CreateLabelsFromType(
ClrType objectType,
ulong objectAddress,
ulong offsetBase,
(int index, int offset) first = default
) {
MemoryInspectionLabel[] labels;
if (objectType.IsArray) {
var length = objectType.Heap.GetObject(objectAddress).AsArray().Length;
labels = new MemoryInspectionLabel[first.index + 1 + length];
labels[first.index] = new MemoryInspectionLabel("length", first.offset, IntPtr.Size);
for (var i = 0; i < length; i++) {
var elementAddress = objectType.GetArrayElementAddress(objectAddress, i);
var offset = (int)(elementAddress - offsetBase);
labels[first.index + 1 + i] = new MemoryInspectionLabel(
i.ToString(),
offset,
objectType.ComponentSize,
GetNestedLabels(objectType.ComponentType!, elementAddress, offsetBase)
);
}
return labels;
}
var title = type.IsValueType
? $"{type.FullName}"
: $"Pointer to {type.FullName}";

var fields = objectType.Fields;
var fieldCount = fields.Length;
labels = new MemoryInspectionLabel[first.index + fieldCount];
for (var i = 0; i < fieldCount; i++) {
var field = fields[i];
if (field.Type == null)
throw new ClrInformationNotFoundException($"Could not get type for field {field.Name}.");

var fieldAddress = field.GetAddress(objectAddress);
var offset = (int)(fieldAddress - offsetBase);
labels[first.index + i] = new MemoryInspectionLabel(
field.Name ?? "",
return new MemoryInspection(title, labels, data);
}

private static byte[] ReadMemory(ClrRuntime runtime, ulong address, ulong size) {
var data = new byte[size];
runtime.DataTarget!.DataReader.Read(address, data);
return data;
}

private MemoryInspectionLabel[] CreateLabelsFromType(
ClrType objectType,
ulong objectAddress,
ulong offsetBase,
(int index, int offset) first = default
) {
MemoryInspectionLabel[] labels;
if (objectType.IsArray) {
var length = objectType.Heap.GetObject(objectAddress).AsArray().Length;
labels = new MemoryInspectionLabel[first.index + 1 + length];
labels[first.index] = new MemoryInspectionLabel("length", first.offset, IntPtr.Size);
for (var i = 0; i < length; i++) {
var elementAddress = objectType.GetArrayElementAddress(objectAddress, i);
var offset = (int)(elementAddress - offsetBase);
labels[first.index + 1 + i] = new MemoryInspectionLabel(
i.ToString(),
offset,
field.Size,
GetNestedLabels(field.Type, fieldAddress, offsetBase)
objectType.ComponentSize,
GetNestedLabels(objectType.ComponentType!, elementAddress, offsetBase)
);
}
return labels;
}

private IReadOnlyList<MemoryInspectionLabel> GetNestedLabels(ClrType type, ulong valueAddress, ulong offsetBase) {
if (type.IsPrimitive || !type.IsValueType)
return Array.Empty<MemoryInspectionLabel>();

return CreateLabelsFromType(type, valueAddress, offsetBase + (uint)IntPtr.Size);
var fields = objectType.Fields;
var fieldCount = fields.Length;
labels = new MemoryInspectionLabel[first.index + fieldCount];
for (var i = 0; i < fieldCount; i++) {
var field = fields[i];
if (field.Type == null)
throw new ClrInformationNotFoundException($"Could not get type for field {field.Name}.");

var fieldAddress = field.GetAddress(objectAddress);
var offset = (int)(fieldAddress - offsetBase);
labels[first.index + i] = new MemoryInspectionLabel(
field.Name ?? "",
offset,
field.Size,
GetNestedLabels(field.Type, fieldAddress, offsetBase)
);
}
return labels;
}

private static unsafe IntPtr GetHeapPointer(object @object) {
var indirect = Unsafe.AsPointer(ref @object);
return **(IntPtr**)(&indirect);
}
private IReadOnlyList<MemoryInspectionLabel> GetNestedLabels(ClrType type, ulong valueAddress, ulong offsetBase) {
if (type.IsPrimitive || !type.IsValueType)
return Array.Empty<MemoryInspectionLabel>();

return CreateLabelsFromType(type, valueAddress, offsetBase + (uint)IntPtr.Size);
}

private static unsafe IntPtr GetHeapPointer(object @object) {
var indirect = Unsafe.AsPointer(ref @object);
return **(IntPtr**)(&indirect);
}
}
2 changes: 1 addition & 1 deletion source/NetFramework/Runtime/Inspect.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static void Heap(object @object) {
if (objectType == null)
throw new Exception($"Failed to find object type for address 0x{address:X}.");

var objectSize = runtime.Heap.GetObjectSize(address, objectType);
var objectSize = runtime.Heap.GetObject(address, objectType).Size;

// Move by one pointer size back -- Object Header,
// see https://blogs.msdn.microsoft.com/seteplia/2017/05/26/managed-object-internals-part-1-layout/
Expand Down
4 changes: 2 additions & 2 deletions source/NetFramework/Runtime/Runtime.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="2.0.226801" />
<PackageReference Include="Microsoft.Diagnostics.Runtime" Version="3.1.512801" />
<PackageReference Include="System.Memory" Version="4.5.4" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="5.0.0" />
<PackageReference Include="System.Runtime.CompilerServices.Unsafe" Version="6.0.0" />
</ItemGroup>
</Project>
Loading

0 comments on commit 39d93b5

Please sign in to comment.