Skip to content

Commit

Permalink
Add DIA interfaces/wrappers
Browse files Browse the repository at this point in the history
  • Loading branch information
lordmilko committed Nov 14, 2023
1 parent a7e2272 commit 7057b34
Show file tree
Hide file tree
Showing 237 changed files with 54,331 additions and 466 deletions.
3 changes: 2 additions & 1 deletion ClrDebug.Tests/DbgEng/DebugAdvancedRequestTests.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using ClrDebug.DbgEng;
using ClrDebug.DIA;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace ClrDebug.Tests.DbgEng
Expand Down Expand Up @@ -47,7 +48,7 @@ public void DebugAdvanced_Request_ExtTDOP_SetFromExpr()

var result = Requests.ExtTypedDataAnsi().SetFromExpr("(ntdll!_PEB*)@$peb");

Assert.AreEqual(SymTag.PointerType, result.Tag);
Assert.AreEqual(SymTagEnum.PointerType, result.Tag);
}
}
}
3 changes: 3 additions & 0 deletions ClrDebug/Extensions/ComObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ namespace ClrDebug
{
public class ComObject<T> : IEquatable<ComObject<T>>
{
/// <summary>
/// Gets the RCW that this object encapsulates.
/// </summary>
public T Raw { get; }

protected ComObject(T raw)
Expand Down
215 changes: 215 additions & 0 deletions ClrDebug/Extensions/DIA/Extensions.As.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
using System;

namespace ClrDebug.DIA
{
public static partial class DiaExtensions
{
#region DiaEnumDebugStreamData

/// <summary>
/// Creates a <see cref="ComObject{T}"/> around an interface supported by the <see cref="IDiaEnumDebugStreamData"/> interface.<para/>
/// Possible conversions include <see cref="DiaImageData"/> and <see cref="DiaEnumDebugStreamData"/>.
/// </summary>
/// <typeparam name="T">A type that wraps one of the interfaces <see cref="IDiaEnumDebugStreamData"/> supports.</typeparam>
/// <param name="diaEnumDebugStreamData">The existing wrapper to create the new wrapper from.</param>
/// <returns>A wrapper of type <typeparamref name="T"/>.</returns>
/// <exception cref="NotSupportedException">A type is specified that is not known to this function.</exception>
public static T As<T>(this DiaEnumDebugStreamData diaEnumDebugStreamData)
{
var t = typeof(T);
object result;

var raw = diaEnumDebugStreamData.Raw;

if (t == typeof(DiaImageData))
result = new DiaImageData((IDiaImageData) raw);
else if (t == typeof(DiaEnumDebugStreamData))
result = diaEnumDebugStreamData;
else
throw Extensions.GetAsNotSupportedException<T, IDiaEnumDebugStreamData>();

return (T) result;
}

#endregion
#region As<DiaPropertyStorage>

/// <summary>
/// Creates a <see cref="ComObject{T}"/> around an interface supported by the <see cref="IDiaSectionContrib"/> interface.<para/>
/// The only supported conversion is <see cref="DiaPropertyStorage"/>.
/// </summary>
/// <typeparam name="T">The <see cref="DiaPropertyStorage"/> type.</typeparam>
/// <param name="diaSectionContrib">The existing wrapper to create the new wrapper from.</param>
/// <returns>A wrapper of type <typeparamref name="T"/>.</returns>
/// <exception cref="NotSupportedException">A type is specified that is not known to this function.</exception>
public static T As<T>(this DiaSectionContrib diaSectionContrib) where T : DiaPropertyStorage =>
(T) AsDiaPropertyStorage(diaSectionContrib.Raw);

/// <summary>
/// Creates a <see cref="ComObject{T}"/> around an interface supported by the <see cref="IDiaSegment"/> interface.<para/>
/// The only supported conversion is <see cref="DiaPropertyStorage"/>.
/// </summary>
/// <typeparam name="T">The <see cref="DiaPropertyStorage"/> type.</typeparam>
/// <param name="diaSegment">The existing wrapper to create the new wrapper from.</param>
/// <returns>A wrapper of type <typeparamref name="T"/>.</returns>
/// <exception cref="NotSupportedException">A type is specified that is not known to this function.</exception>
public static T As<T>(this DiaSegment diaSegment) where T : DiaPropertyStorage =>
(T) AsDiaPropertyStorage(diaSegment.Raw);

/// <summary>
/// Creates a <see cref="ComObject{T}"/> around an interface supported by the <see cref="IDiaInjectedSource"/> interface.<para/>
/// The only supported conversion is <see cref="DiaPropertyStorage"/>.
/// </summary>
/// <typeparam name="T">The <see cref="DiaPropertyStorage"/> type.</typeparam>
/// <param name="diaInjectedSource">The existing wrapper to create the new wrapper from.</param>
/// <returns>A wrapper of type <typeparamref name="T"/>.</returns>
/// <exception cref="NotSupportedException">A type is specified that is not known to this function.</exception>
public static T As<T>(this DiaInjectedSource diaInjectedSource) where T : DiaPropertyStorage =>
(T) AsDiaPropertyStorage(diaInjectedSource.Raw);

/// <summary>
/// Creates a <see cref="ComObject{T}"/> around an interface supported by the <see cref="IDiaFrameData"/> interface.<para/>
/// The only supported conversion is <see cref="DiaPropertyStorage"/>.
/// </summary>
/// <typeparam name="T">The <see cref="DiaPropertyStorage"/> type.</typeparam>
/// <param name="diaFrameData">The existing wrapper to create the new wrapper from.</param>
/// <returns>A wrapper of type <typeparamref name="T"/>.</returns>
/// <exception cref="NotSupportedException">A type is specified that is not known to this function.</exception>
public static T As<T>(this DiaFrameData diaFrameData) where T : DiaPropertyStorage =>
(T) AsDiaPropertyStorage(diaFrameData.Raw);

/// <summary>
/// Creates a <see cref="ComObject{T}"/> around an interface supported by the <see cref="IDiaSymbol"/> interface.<para/>
/// The only supported conversion is <see cref="DiaPropertyStorage"/>.
/// </summary>
/// <typeparam name="T">The <see cref="DiaPropertyStorage"/> type.</typeparam>
/// <param name="diaSymbol">The existing wrapper to create the new wrapper from.</param>
/// <returns>A wrapper of type <typeparamref name="T"/>.</returns>
/// <exception cref="NotSupportedException">A type is specified that is not known to this function.</exception>
public static T As<T>(this DiaSymbol diaSymbol) where T : DiaPropertyStorage =>
(T) AsDiaPropertyStorage(diaSymbol.Raw);

/// <summary>
/// Creates a <see cref="ComObject{T}"/> around an interface supported by the <see cref="IDiaSourceFile"/> interface.<para/>
/// The only supported conversion is <see cref="DiaPropertyStorage"/>.
/// </summary>
/// <typeparam name="T">The <see cref="DiaPropertyStorage"/> type.</typeparam>
/// <param name="diaSourceFile">The existing wrapper to create the new wrapper from.</param>
/// <returns>A wrapper of type <typeparamref name="T"/>.</returns>
/// <exception cref="NotSupportedException">A type is specified that is not known to this function.</exception>
public static T As<T>(this DiaSourceFile diaSourceFile) where T : DiaPropertyStorage =>
(T) AsDiaPropertyStorage(diaSourceFile.Raw);

/// <summary>
/// Creates a <see cref="ComObject{T}"/> around an interface supported by the <see cref="IDiaLineNumber"/> interface.<para/>
/// The only supported conversion is <see cref="DiaPropertyStorage"/>.
/// </summary>
/// <typeparam name="T">The <see cref="DiaPropertyStorage"/> type.</typeparam>
/// <param name="diaLineNumber">The existing wrapper to create the new wrapper from.</param>
/// <returns>A wrapper of type <typeparamref name="T"/>.</returns>
/// <exception cref="NotSupportedException">A type is specified that is not known to this function.</exception>
public static T As<T>(this DiaLineNumber diaLineNumber) where T : DiaPropertyStorage =>
(T) AsDiaPropertyStorage(diaLineNumber.Raw);

private static object AsDiaPropertyStorage<T>(T value) =>
new DiaPropertyStorage((IDiaPropertyStorage) value);

#endregion
#region DiaTable

/// <summary>
/// Creates a <see cref="ComObject{T}"/> around an interface supported by the <see cref="IDiaTable"/> interface.<para/>
/// Each <see cref="IDiaTable"/> instance is in fact an enumerator for iterating over one and only one type of resource.
/// To locate the <see cref="IDiaTable"/> that implements given enumerator interface, see the <see cref="GetTable{T}(DiaSession)"/> extension
/// method. This method should only be used when you already know for certain which enumerator a given <see cref="IDiaTable"/> represents.
/// Possible conversions include <see cref="DiaEnumSymbols"/>, <see cref="DiaEnumSourceFiles"/>, <see cref="DiaEnumLineNumbers"/>,
/// <see cref="DiaEnumSectionContribs"/>, <see cref="DiaEnumSegments"/>, <see cref="DiaEnumInjectedSources"/>
/// and <see cref="DiaEnumFrameData"/>.
/// </summary>
/// <typeparam name="T">A type that wraps one of the interfaces <see cref="IDiaTable"/> supports.</typeparam>
/// <param name="diaTable">The existing wrapper to create the new wrapper from.</param>
/// <returns>A wrapper of type <typeparamref name="T"/>.</returns>
/// <exception cref="NotSupportedException">A type is specified that is not known to this function.</exception>
private static T As<T>(this DiaTable diaTable)
{
//This method is implemented for completeness, however due to the fact that each IDiaTable exclusively implements one of the available
//enumerator interfaces, it is inherently unsafe to forcefully cast an IDiaTable to a given interface. To locate the IDiaTable
//that implements a given enumerator, use the GetTable<T>() extension method.

var t = typeof(T);
object result;

var raw = diaTable.Raw;

Exception invalidTable<TInterface>()
{
throw new InvalidCastException(
$"Cannot convert the specified {nameof(IDiaTable)} instance to type '{typeof(TInterface).Name}': interface '{typeof(TInterface).Name}' is not supported. " +
$"Each {nameof(IDiaTable)} represents a specific type of enumerator. To locate the {nameof(IDiaTable)} that contains a specific " +
$"type of enumerator, please see the {nameof(GetTable)}<T>() extension method."
);
}

if (t == typeof(DiaEnumSymbols))
{
if (raw is IDiaEnumSymbols i)
result = new DiaEnumSymbols(i);
else
throw invalidTable<IDiaEnumSymbols>();
}
else if (t == typeof(DiaEnumSourceFiles))
{
if (raw is IDiaEnumSourceFiles i)
result = new DiaEnumSourceFiles(i);
else
throw invalidTable<IDiaEnumSymbols>();
}

else if (t == typeof(DiaEnumLineNumbers))
{
if (raw is IDiaEnumLineNumbers i)
result = new DiaEnumLineNumbers(i);
else
throw invalidTable<IDiaEnumSymbols>();
}

else if (t == typeof(DiaEnumSectionContribs))
{
if (raw is IDiaEnumSectionContribs i)
result = new DiaEnumSectionContribs(i);
else
throw invalidTable<IDiaEnumSymbols>();
}

else if (t == typeof(DiaEnumSegments))
{
if (raw is IDiaEnumSegments i)
result = new DiaEnumSegments(i);
else
throw invalidTable<IDiaEnumSymbols>();
}

else if (t == typeof(DiaEnumInjectedSources))
{
if (raw is IDiaEnumInjectedSources i)
result = new DiaEnumInjectedSources(i);
else
throw invalidTable<IDiaEnumSymbols>();
}

else if (t == typeof(DiaEnumFrameData))
{
if (raw is IDiaEnumFrameData i)
result = new DiaEnumFrameData(i);
else
throw invalidTable<IDiaEnumSymbols>();
}
else
throw Extensions.GetAsNotSupportedException<T, IDiaTable>();

return (T) result;
}

#endregion
}
}
60 changes: 60 additions & 0 deletions ClrDebug/Extensions/DIA/Extensions.DiaSession.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
using System;

namespace ClrDebug.DIA
{
public static partial class DiaExtensions
{
/// <summary>
/// Locates the table that implements the specified enumerator type from the specified <see cref="DiaSession"/>.<para/>
/// Possible tables include <see cref="DiaEnumSymbols"/>, <see cref="DiaEnumSourceFiles"/>, <see cref="DiaEnumLineNumbers"/>,
/// <see cref="DiaEnumSectionContribs"/>, <see cref="DiaEnumSegments"/>, <see cref="DiaEnumInjectedSources"/>
/// and <see cref="DiaEnumFrameData"/>.
/// </summary>
/// <typeparam name="T">The type of table to retrieve.</typeparam>
/// <param name="diaSession">The session to get the table from.</param>
/// <returns>The specified enumerator wrapper.</returns>
public static T GetTable<T>(this DiaSession diaSession)
{
/* The IDiaSession.getEnumTables member is special. Contrary to what you might think, it doesn't
* return a mere collection of "table objects"; rather, it returns a collection of "table enumerators".
* You iterate over this collection of table enumerators to find the specific table enumerator you're
* after. e.g. if you want to get information source files, you ask for the source file enumerator table.
* Once you've found the enumerator table you're after, thats it */

TInterface getTableInternal<TInterface>(DiaEnumTables tables) where TInterface : class
{
foreach (var table in tables)
{
if (table.Raw is TInterface qi)
return qi;
}

throw new NotSupportedException($"Could not find an {nameof(IDiaTable)} that implements interface {typeof(TInterface).Name}");
}

var t = typeof(T);
object result;

var enumTables = diaSession.EnumTables;

if (t == typeof(DiaEnumSymbols))
result = new DiaEnumSymbols(getTableInternal<IDiaEnumSymbols>(enumTables));
else if (t == typeof(DiaEnumSourceFiles))
result = new DiaEnumSourceFiles(getTableInternal<IDiaEnumSourceFiles>(enumTables));
else if (t == typeof(DiaEnumLineNumbers))
result = new DiaEnumLineNumbers(getTableInternal<IDiaEnumLineNumbers>(enumTables));
else if (t == typeof(DiaEnumSectionContribs))
result = new DiaEnumSectionContribs(getTableInternal<IDiaEnumSectionContribs>(enumTables));
else if (t == typeof(DiaEnumSegments))
result = new DiaEnumSegments(getTableInternal<IDiaEnumSegments>(enumTables));
else if (t == typeof(DiaEnumInjectedSources))
result = new DiaEnumInjectedSources(getTableInternal<IDiaEnumInjectedSources>(enumTables));
else if (t == typeof(DiaEnumFrameData))
result = new DiaEnumFrameData(getTableInternal<IDiaEnumFrameData>(enumTables));
else
throw Extensions.GetAsNotSupportedException<T, IDiaTable>();

return (T) result;
}
}
}
Loading

0 comments on commit 7057b34

Please sign in to comment.