Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[cdac] break up cdacreader into 4 separate assemblies #108156

Merged
merged 18 commits into from
Sep 30, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,4 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts;
internal interface IContract
{
static virtual string Name => throw new NotImplementedException();
static virtual IContract Create(Target target, int version) => throw new NotImplementedException();
}
Original file line number Diff line number Diff line change
@@ -1,26 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// 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;
using System.Linq;
using System.Text;
lambdageek marked this conversation as resolved.
Show resolved Hide resolved
using System.Threading.Tasks;

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

internal interface IDacStreams : IContract
{
static string IContract.Name { get; } = nameof(DacStreams);
static IContract IContract.Create(Target target, int version)
{
return version switch
{
1 => new DacStreams_1(target),
_ => default(DacStreams),
};
}

public virtual string? StringFromEEAddress(TargetPointer address) => throw new NotImplementedException();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts;
internal interface IEcmaMetadata : IContract
{
static string IContract.Name { get; } = nameof(EcmaMetadata);
static IContract IContract.Create(Target target, int version)
{
return version switch
{
1 => new EcmaMetadata_1(target),
_ => default(EcmaMetadata),
};
}

public virtual TargetSpan GetReadOnlyMetadataAddress(ModuleHandle handle) => throw new NotImplementedException();

public virtual MetadataReader? GetMetadata(ModuleHandle module) => throw new NotImplementedException();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,6 @@ internal record struct ExceptionData(
internal interface IException : IContract
{
static string IContract.Name { get; } = nameof(Exception);
static IContract IContract.Create(Target target, int version)
{
return version switch
{
1 => new Exception_1(target),
_ => default(Exception),
};
}

public virtual TargetPointer GetNestedExceptionInfo(TargetPointer exception, out TargetPointer nextNestedException) => throw new NotImplementedException();
public virtual ExceptionData GetExceptionData(TargetPointer managedException) => throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,14 +35,6 @@ internal record struct ModuleLookupTables(
internal interface ILoader : IContract
{
static string IContract.Name => nameof(Loader);
static IContract IContract.Create(Target target, int version)
{
return version switch
{
1 => new Loader_1(target),
_ => default(Loader),
};
}

public virtual ModuleHandle GetModuleHandle(TargetPointer modulePointer) => throw new NotImplementedException();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,23 +8,7 @@ namespace Microsoft.Diagnostics.DataContractReader.Contracts;
internal interface IObject : IContract
{
static string IContract.Name { get; } = nameof(Object);
static IContract IContract.Create(Target target, int version)
{
ulong methodTableOffset = (ulong)target.GetTypeInfo(DataType.Object).Fields["m_pMethTab"].Offset;
byte objectToMethodTableUnmask = target.ReadGlobal<byte>(Constants.Globals.ObjectToMethodTableUnmask);
TargetPointer stringMethodTable = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.StringMethodTable));
TargetPointer syncTableEntries = target.ReadPointer(
target.ReadGlobalPointer(Constants.Globals.SyncTableEntries));
return version switch
{
1 => new Object_1(target, methodTableOffset, objectToMethodTableUnmask, stringMethodTable, syncTableEntries),
_ => default(Object),
};
}

public virtual TargetPointer GetMethodTableAddress(TargetPointer address) => throw new NotImplementedException();

public virtual string GetStringValue(TargetPointer address) => throw new NotImplementedException();
public virtual TargetPointer GetArrayData(TargetPointer address, out uint count, out TargetPointer boundsStart, out TargetPointer lowerBounds) => throw new NotImplementedException();
public virtual bool GetBuiltInComData(TargetPointer address, out TargetPointer rcw, out TargetPointer ccw) => throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// 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 interface IRegistry
AaronRobinsonMSFT marked this conversation as resolved.
Show resolved Hide resolved
{
public IException Exception { get;}
public ILoader Loader { get; }
public IEcmaMetadata EcmaMetadata { get; }
public IObject Object { get; }
public IThread Thread { get; }
public IRuntimeTypeSystem RuntimeTypeSystem { get; }
public IDacStreams DacStreams { get; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -76,17 +76,6 @@ public enum ArrayFunctionType
internal interface IRuntimeTypeSystem : IContract
{
static string IContract.Name => nameof(RuntimeTypeSystem);
static IContract IContract.Create(Target target, int version)
{
TargetPointer targetPointer = target.ReadGlobalPointer(Constants.Globals.FreeObjectMethodTable);
TargetPointer freeObjectMethodTable = target.ReadPointer(targetPointer);
ulong methodDescAlignment = target.ReadGlobal<ulong>(Constants.Globals.MethodDescAlignment);
return version switch
{
1 => new RuntimeTypeSystem_1(target, freeObjectMethodTable, methodDescAlignment),
_ => default(RuntimeTypeSystem),
};
}

#region TypeHandle inspection APIs
public virtual TypeHandle GetTypeHandle(TargetPointer address) => throw new NotImplementedException();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;

namespace Microsoft.Diagnostics.DataContractReader.Contracts;

internal record struct ThreadStoreData(
lambdageek marked this conversation as resolved.
Show resolved Hide resolved
int ThreadCount,
TargetPointer FirstThread,
TargetPointer FinalizerThread,
TargetPointer GCThread);

internal record struct ThreadStoreCounts(
int UnstartedThreadCount,
int BackgroundThreadCount,
int PendingThreadCount,
int DeadThreadCount);

[Flags]
internal enum ThreadState
{
Unknown = 0x00000000,
Hijacked = 0x00000080, // Return address has been hijacked
Background = 0x00000200, // Thread is a background thread
Unstarted = 0x00000400, // Thread has never been started
Dead = 0x00000800, // Thread is dead
ThreadPoolWorker = 0x01000000, // Thread is a thread pool worker thread
}

internal record struct ThreadData(
uint Id,
TargetNUInt OSId,
ThreadState State,
bool PreemptiveGCDisabled,
TargetPointer AllocContextPointer,
TargetPointer AllocContextLimit,
TargetPointer Frame,
TargetPointer FirstNestedException,
TargetPointer TEB,
TargetPointer LastThrownObjectHandle,
TargetPointer NextThread);

internal interface IThread : IContract
{
static string IContract.Name { get; } = nameof(Thread);

public virtual ThreadStoreData GetThreadStoreData() => throw new NotImplementedException();
public virtual ThreadStoreCounts GetThreadCounts() => throw new NotImplementedException();
public virtual ThreadData GetThreadData(TargetPointer thread) => throw new NotImplementedException();
}

internal readonly struct Thread : IThread
{
// Everything throws NotImplementedException
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ namespace Microsoft.Diagnostics.DataContractReader.Data;

internal interface IData<TSelf> where TSelf : IData<TSelf>
{
static abstract TSelf Create(Target target, TargetPointer address);
static abstract TSelf Create(ITarget target, TargetPointer address);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System;

namespace Microsoft.Diagnostics.DataContractReader;

internal interface IContractFactory<out TProduct> where TProduct : Contracts.IContract
{
TProduct CreateContract(ITarget target, int version);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// 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;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;

namespace Microsoft.Diagnostics.DataContractReader;

/// <summary>
/// Representation of the target under inspection
/// </summary>
/// <remarks>
/// This class provides APIs used by contracts for reading from the target and getting type and globals
/// information based on the target's contract descriptor. Like the contracts themselves in cdacreader,
/// these are throwing APIs. Any callers at the boundaries (for example, unmanaged entry points, COM)
/// should handle any exceptions.
/// </remarks>
internal interface ITarget
{
int PointerSize { get; }
lambdageek marked this conversation as resolved.
Show resolved Hide resolved

TargetPointer ReadGlobalPointer(string global);

/// <summary>
/// Read a pointer from the target in target endianness
/// </summary>
/// <param name="address">Address to start reading from</param>
/// <returns>Pointer read from the target</returns>}
TargetPointer ReadPointer(ulong address);

void ReadBuffer(ulong address, Span<byte> buffer);

/// <summary>
/// Read a null-terminated UTF-8 string from the target
/// </summary>
/// <param name="address">Address to start reading from</param>
/// <returns>String read from the target</returns>}
public string ReadUtf8String(ulong address);

/// <summary>
/// Read a null-terminated UTF-16 string from the target in target endianness
/// </summary>
/// <param name="address">Address to start reading from</param>
/// <returns>String read from the target</returns>}
public string ReadUtf16String(ulong address);

/// <summary>
/// Read a native unsigned integer from the target in target endianness
/// </summary>
/// <param name="address">Address to start reading from</param>
/// <returns>Value read from the target</returns>
public TargetNUInt ReadNUInt(ulong address);

T ReadGlobal<T>(string name) where T : struct, INumber<T>;
lambdageek marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Read a value from the target in target endianness
/// </summary>
/// <typeparam name="T">Type of value to read</typeparam>
/// <param name="address">Address to start reading from</param>
/// <returns>Value read from the target</returns>
public T Read<T>(ulong address) where T : unmanaged, IBinaryInteger<T>, IMinMaxValue<T>;

public bool IsAlignedToPointerSize(TargetPointer pointer);

TypeInfo GetTypeInfo(DataType type);

IDataCache ProcessedData { get; }
lambdageek marked this conversation as resolved.
Show resolved Hide resolved

public interface IDataCache
{
T GetOrAdd<T>(TargetPointer address) where T : Data.IData<T>;
bool TryGet<T>(ulong address, [NotNullWhen(true)] out T? data);
}

public readonly record struct TypeInfo
{
public uint? Size { get; init; }
public readonly IReadOnlyDictionary<string, FieldInfo> Fields
{
get;
init;
}

public TypeInfo()
{
Fields = new Dictionary<string, FieldInfo>();
}
}

public readonly record struct FieldInfo
{
public int Offset {get; init; }
public readonly DataType Type {get; init;}
public readonly string? TypeName {get; init; }
}

Contracts.IRegistry Contracts { get; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>$(NetCoreAppToolCurrent)</TargetFramework>
<RootNamespace>Microsoft.Diagnostics.DataContractReader</RootNamespace>
<Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<!-- Do not produce a public package. This ships as part of the runtime -->
<IsShippingPackage>false</IsShippingPackage>
<InvariantGlobalization>true</InvariantGlobalization>
<JsonSerializerIsReflectionEnabledByDefault>false</JsonSerializerIsReflectionEnabledByDefault>
</PropertyGroup>

<ItemGroup>
<InternalsVisibleTo Include="Microsoft.Diagnostics.DataContractReader.Tests" />
<InternalsVisibleTo Include="Microsoft.Diagnostics.DataContractReader.Contracts" />
<InternalsVisibleTo Include="Microsoft.Diagnostics.DataContractReader" />
<InternalsVisibleTo Include="cdacreader" Condition="'$(TargetsWindows)' == 'true'"/>
<InternalsVisibleTo Include="libcdacreader" Condition="'$(TargetsWindows)' != 'true'"/>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;

namespace Microsoft.Diagnostics.DataContractReader;

public readonly struct TargetNUInt
{
public readonly ulong Value;
public TargetNUInt(ulong value) => Value = value;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System;

namespace Microsoft.Diagnostics.DataContractReader;

public readonly struct TargetPointer : IEquatable<TargetPointer>
{
public static TargetPointer Null = new(0);
public static TargetPointer Max32Bit = new(uint.MaxValue);
public static TargetPointer Max64Bit = new(ulong.MaxValue);

public readonly ulong Value;
public TargetPointer(ulong value) => Value = value;

public static implicit operator ulong(TargetPointer p) => p.Value;
public static implicit operator TargetPointer(ulong v) => new TargetPointer(v);

public static bool operator ==(TargetPointer left, TargetPointer right) => left.Value == right.Value;
public static bool operator !=(TargetPointer left, TargetPointer right) => left.Value != right.Value;

public override bool Equals(object? obj) => obj is TargetPointer pointer && Equals(pointer);
public bool Equals(TargetPointer other) => Value == other.Value;

public override int GetHashCode() => Value.GetHashCode();
}
Loading
Loading