Browse Source

Add Offset and friendly Kind columns to the CustomDebugInformation table

WPF showed a row Offset column and decoded the Kind GUID into one cell
combining heap offset, friendly name, and raw GUID; the Avalonia table
only carried the bare heap offsets. Offset follows the GetRowOffset
convention every other table uses. Kind is plain text rather than a
hex column plus tooltip so the per-column filter matches the friendly
names.

Assisted-by: Claude:claude-fable-5[1m]:Claude Code
pull/3759/head
Siegfried Pammer 4 weeks ago
parent
commit
98b5190752
  1. 20
      ILSpy.Tests/Metadata/CustomDebugInformationRowDetailsTests.cs
  2. 54
      ILSpy/Metadata/DebugTables/CustomDebugInformationTableTreeNode.cs

20
ILSpy.Tests/Metadata/CustomDebugInformationRowDetailsTests.cs

@ -138,6 +138,26 @@ public class CustomDebugInformationRowDetailsTests @@ -138,6 +138,26 @@ public class CustomDebugInformationRowDetailsTests
.Select(h => new CustomDebugInformationEntry(metadataFile, h))
.ToList();
[Test]
public void Offset_And_Friendly_Kind_Columns_Match_The_Tables_Conventions()
{
// The Kind column carries the GUID heap offset, the decoded friendly name, and the
// raw GUID in one cell; Offset positions the row within the metadata stream like
// every other table's Offset column.
var metadataFile = BuildPdbFixture();
var entries = LoadEntries(metadataFile);
entries[0].Kind.Should().MatchRegex("^[0-9A-F]{8} - Source Link \\(C# / VB\\) \\[cc110556-a091-4d38-9fec-25ab9a351a6a\\]$");
entries[1].Kind.Should().EndWith($"- Unknown [{UnknownKindGuid}]");
entries[3].Kind.Should().Contain("State Machine Hoisted Local Scopes (C# / VB)");
int rowSize = metadataFile.Metadata.GetTableRowSize(TableIndex.CustomDebugInformation);
entries[0].Offset.Should().BePositive("the table lives at a real offset inside the PDB metadata");
entries.Select(e => e.Offset).Should().BeInAscendingOrder()
.And.HaveCount(7);
(entries[1].Offset - entries[0].Offset).Should().Be(rowSize);
}
[Test]
public void RowDetails_Parses_The_Structured_Kinds_Into_Typed_Rows()
{

54
ILSpy/Metadata/DebugTables/CustomDebugInformationTableTreeNode.cs

@ -45,9 +45,9 @@ namespace ILSpy.Metadata.DebugTables @@ -45,9 +45,9 @@ namespace ILSpy.Metadata.DebugTables
/// <summary>
/// View of the CustomDebugInformation table — extensible per-entity payloads used for
/// async/iterator state-machine info, embedded source, source-link JSON, and similar
/// debug-time data. Each row carries a Parent token, a Kind GUID, and an opaque Value
/// blob. The friendly-name decoding of well-known Kind GUIDs (StateMachineHoistedLocalScopes,
/// SourceLink, etc.) is deferred until the Phase 4 cell-tooltip work.
/// debug-time data. Each row carries a Parent token, a Kind GUID (decoded to a friendly
/// name in the Kind column), and an opaque Value blob whose parsed contents show as the
/// row's details.
/// </summary>
public sealed class CustomDebugInformationTableTreeNode : MetadataTableTreeNode<CustomDebugInformationTableTreeNode.CustomDebugInformationEntry>
{
@ -106,14 +106,58 @@ namespace ILSpy.Metadata.DebugTables @@ -106,14 +106,58 @@ namespace ILSpy.Metadata.DebugTables
[ColumnInfo("X8")]
public int Token => MetadataTokens.GetToken(handle);
[ColumnInfo("X8")]
public int Offset => GetRowOffset(metadataFile, TableIndex.CustomDebugInformation, RID);
[ColumnInfo("X8", Kind = ColumnKind.Token)]
public int Parent => MetadataTokens.GetToken(debugInfo.Parent);
string? parentTooltip;
public string? ParentTooltip => GenerateTooltip(ref parentTooltip, metadataFile, debugInfo.Parent);
[ColumnInfo("X8", Kind = ColumnKind.HeapOffset)]
public int Kind => MetadataTokens.GetHeapOffset(debugInfo.Kind);
static readonly (Guid Guid, string Name)[] knownKindNames = {
(KnownGuids.StateMachineHoistedLocalScopes, "State Machine Hoisted Local Scopes (C# / VB)"),
(KnownGuids.DynamicLocalVariables, "Dynamic Local Variables (C#)"),
(KnownGuids.DefaultNamespaces, "Default Namespaces (VB)"),
(KnownGuids.EditAndContinueLocalSlotMap, "Edit And Continue Local Slot Map (C# / VB)"),
(KnownGuids.EditAndContinueLambdaAndClosureMap, "Edit And Continue Lambda And Closure Map (C# / VB)"),
(KnownGuids.EncStateMachineStateMap, "Edit And Continue State Machine State Map (C# / VB)"),
(KnownGuids.EmbeddedSource, "Embedded Source (C# / VB)"),
(KnownGuids.SourceLink, "Source Link (C# / VB)"),
(KnownGuids.MethodSteppingInformation, "Method Stepping Information (C# / VB)"),
(KnownGuids.CompilationOptions, "Compilation Options (C# / VB)"),
(KnownGuids.CompilationMetadataReferences, "Compilation Metadata References (C# / VB)"),
(KnownGuids.TupleElementNames, "Tuple Element Names (C#)"),
(KnownGuids.TypeDefinitionDocuments, "Type Definition Documents (C# / VB)"),
};
string? kindString;
/// <summary>
/// One cell carrying the GUID heap offset, the decoded friendly name of well-known
/// kind GUIDs, and the raw GUID, e.g.
/// <c>0000000B - Source Link (C# / VB) [cc110556-...]</c>. Plain text (instead of a
/// bare heap offset plus tooltip) so the column filter matches the friendly names.
/// </summary>
public string Kind {
get {
if (kindString != null)
return kindString;
if (debugInfo.Kind.IsNil)
return kindString = "";
var guid = metadataFile.Metadata.GetGuid(debugInfo.Kind);
string name = "Unknown";
foreach (var (knownGuid, knownName) in knownKindNames)
{
if (guid == knownGuid)
{
name = knownName;
break;
}
}
return kindString = $"{MetadataTokens.GetHeapOffset(debugInfo.Kind):X8} - {name} [{guid}]";
}
}
[ColumnInfo("X8", Kind = ColumnKind.HeapOffset)]
public int Value => MetadataTokens.GetHeapOffset(debugInfo.Value);

Loading…
Cancel
Save