Browse Source

Add support for inline display of blob contents of CustomDebugInformation entries in PDBs.

pull/2326/head
Siegfried Pammer 4 years ago
parent
commit
51dcab484d
  1. 3
      ICSharpCode.Decompiler/DebugInfo/KnownGuids.cs
  2. 1
      ILSpy/Metadata/CoffHeaderTreeNode.cs
  3. 238
      ILSpy/Metadata/DebugTables/CustomDebugInformationTableTreeNode.cs
  4. 2
      ILSpy/Metadata/DebugTables/LocalScopeTableTreeNode.cs
  5. 20
      ILSpy/Metadata/Helpers.cs
  6. 21
      ILSpy/Metadata/MetadataTableViews.xaml
  7. 10
      ILSpy/Metadata/MetadataTableViews.xaml.cs

3
ICSharpCode.Decompiler/DebugInfo/KnownGuids.cs

@ -18,6 +18,9 @@ namespace ICSharpCode.Decompiler.DebugInfo @@ -18,6 +18,9 @@ namespace ICSharpCode.Decompiler.DebugInfo
public static readonly Guid EmbeddedSource = new Guid("0e8a571b-6926-466e-b4ad-8ab04611f5fe");
public static readonly Guid SourceLink = new Guid("CC110556-A091-4D38-9FEC-25AB9A351A6A");
public static readonly Guid MethodSteppingInformation = new Guid("54FD2AC5-E925-401A-9C2A-F94F171072F8");
public static readonly Guid CompilationOptions = new Guid("B5FEEC05-8CD0-4A83-96DA-466284BB4BD8");
public static readonly Guid CompilationMetadataReferences = new Guid("7E4D4708-096E-4C5C-AEDA-CB10BA6A740D");
public static readonly Guid TupleElementNames = new Guid("ED9FDF71-8879-4747-8ED3-FE5EDE3CE710");
public static readonly Guid HashAlgorithmSHA1 = new Guid("ff1816ec-aa5e-4d10-87f7-6f4963833460");
public static readonly Guid HashAlgorithmSHA256 = new Guid("8829d00f-11b8-4213-878b-770e8597ac16");

1
ILSpy/Metadata/CoffHeaderTreeNode.cs

@ -111,6 +111,7 @@ namespace ICSharpCode.ILSpy.Metadata @@ -111,6 +111,7 @@ namespace ICSharpCode.ILSpy.Metadata
new { Value = (flags & 0x4000) != 0, Meaning = "<4000> File should only be run on a UP machine" },
new { Value = (flags & 0x8000) != 0, Meaning = "<8000> Bytes of machine words are reversed (High)" },
});
dataGridFactory.SetValue(DataGrid.GridLinesVisibilityProperty, DataGridGridLinesVisibility.None);
DataTemplate template = new DataTemplate();
template.VisualTree = dataGridFactory;
return template;

238
ILSpy/Metadata/DebugTables/CustomDebugInformationTableTreeNode.cs

@ -17,11 +17,15 @@ @@ -17,11 +17,15 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.DebugInfo;
@ -51,6 +55,10 @@ namespace ICSharpCode.ILSpy.Metadata @@ -51,6 +55,10 @@ namespace ICSharpCode.ILSpy.Metadata
tabPage.SupportsLanguageSwitching = false;
var view = Helpers.PrepareDataGrid(tabPage, this);
view.RowDetailsVisibilityMode = DataGridRowDetailsVisibilityMode.VisibleWhenSelected;
view.RowDetailsTemplateSelector = new CustomDebugInformationDetailsTemplateSelector();
var list = new List<CustomDebugInformationEntry>();
CustomDebugInformationEntry scrollTargetEntry = default;
@ -76,6 +84,24 @@ namespace ICSharpCode.ILSpy.Metadata @@ -76,6 +84,24 @@ namespace ICSharpCode.ILSpy.Metadata
return true;
}
class CustomDebugInformationDetailsTemplateSelector : DataTemplateSelector
{
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
var entry = (CustomDebugInformationEntry)item;
switch (entry.kind)
{
case CustomDebugInformationEntry.CustomDebugInformationKind.StateMachineHoistedLocalScopes:
case CustomDebugInformationEntry.CustomDebugInformationKind.CompilationMetadataReferences:
case CustomDebugInformationEntry.CustomDebugInformationKind.CompilationOptions:
case CustomDebugInformationEntry.CustomDebugInformationKind.TupleElementNames:
return (DataTemplate)MetadataTableViews.Instance["CustomDebugInformationDetailsDataGrid"];
default:
return (DataTemplate)MetadataTableViews.Instance["CustomDebugInformationDetailsTextBlob"];
}
}
}
struct CustomDebugInformationEntry
{
readonly int? offset;
@ -83,10 +109,81 @@ namespace ICSharpCode.ILSpy.Metadata @@ -83,10 +109,81 @@ namespace ICSharpCode.ILSpy.Metadata
readonly MetadataReader metadata;
readonly CustomDebugInformationHandle handle;
readonly CustomDebugInformation debugInfo;
internal readonly CustomDebugInformationKind kind;
internal enum CustomDebugInformationKind
{
None,
Unknown,
StateMachineHoistedLocalScopes,
DynamicLocalVariables,
DefaultNamespaces,
EditAndContinueLocalSlotMap,
EditAndContinueLambdaAndClosureMap,
EmbeddedSource,
SourceLink,
MethodSteppingInformation,
CompilationOptions,
CompilationMetadataReferences,
TupleElementNames
}
static CustomDebugInformationKind GetKind(MetadataReader metadata, GuidHandle h)
{
if (h.IsNil)
return CustomDebugInformationKind.None;
var guid = metadata.GetGuid(h);
if (KnownGuids.StateMachineHoistedLocalScopes == guid)
{
return CustomDebugInformationKind.StateMachineHoistedLocalScopes;
}
if (KnownGuids.DynamicLocalVariables == guid)
{
return CustomDebugInformationKind.StateMachineHoistedLocalScopes;
}
if (KnownGuids.DefaultNamespaces == guid)
{
return CustomDebugInformationKind.StateMachineHoistedLocalScopes;
}
if (KnownGuids.EditAndContinueLocalSlotMap == guid)
{
return CustomDebugInformationKind.EditAndContinueLocalSlotMap;
}
if (KnownGuids.EditAndContinueLambdaAndClosureMap == guid)
{
return CustomDebugInformationKind.EditAndContinueLambdaAndClosureMap;
}
if (KnownGuids.EmbeddedSource == guid)
{
return CustomDebugInformationKind.EmbeddedSource;
}
if (KnownGuids.SourceLink == guid)
{
return CustomDebugInformationKind.SourceLink;
}
if (KnownGuids.MethodSteppingInformation == guid)
{
return CustomDebugInformationKind.MethodSteppingInformation;
}
if (KnownGuids.CompilationOptions == guid)
{
return CustomDebugInformationKind.CompilationOptions;
}
if (KnownGuids.CompilationMetadataReferences == guid)
{
return CustomDebugInformationKind.CompilationMetadataReferences;
}
if (KnownGuids.TupleElementNames == guid)
{
return CustomDebugInformationKind.TupleElementNames;
}
return CustomDebugInformationKind.Unknown;
}
public int RID => MetadataTokens.GetRowNumber(handle);
public object Offset => offset == null ? "n/a" : (object)offset;
public object Offset => offset == null ? "n/a" : offset;
[StringFormat("X8")]
public int Parent => MetadataTokens.GetToken(debugInfo.Parent);
@ -100,48 +197,46 @@ namespace ICSharpCode.ILSpy.Metadata @@ -100,48 +197,46 @@ namespace ICSharpCode.ILSpy.Metadata
}
}
[StringFormat("X8")]
public int Kind => MetadataTokens.GetHeapOffset(debugInfo.Kind);
public string KindTooltip {
public string Kind {
get {
if (debugInfo.Kind.IsNil)
return null;
var guid = metadata.GetGuid(debugInfo.Kind);
if (KnownGuids.StateMachineHoistedLocalScopes == guid)
{
return "State Machine Hoisted Local Scopes (C# / VB) [" + guid + "]";
}
if (KnownGuids.DynamicLocalVariables == guid)
{
return "Dynamic Local Variables (C#) [" + guid + "]";
}
if (KnownGuids.DefaultNamespaces == guid)
{
return "Default Namespaces (VB) [" + guid + "]";
}
if (KnownGuids.EditAndContinueLocalSlotMap == guid)
{
return "Edit And Continue Local Slot Map (C# / VB) [" + guid + "]";
}
if (KnownGuids.EditAndContinueLambdaAndClosureMap == guid)
Guid guid;
if (kind != CustomDebugInformationKind.None)
{
return "Edit And Continue Lambda And Closure Map (C# / VB) [" + guid + "]";
guid = metadata.GetGuid(debugInfo.Kind);
}
if (KnownGuids.EmbeddedSource == guid)
else
{
return "Embedded Source (C# / VB) [" + guid + "]";
guid = Guid.Empty;
}
if (KnownGuids.SourceLink == guid)
switch (kind)
{
return "Source Link (C# / VB) [" + guid + "]";
case CustomDebugInformationKind.None:
return null;
case CustomDebugInformationKind.StateMachineHoistedLocalScopes:
return $"{MetadataTokens.GetHeapOffset(debugInfo.Kind):X8} - State Machine Hoisted Local Scopes (C# / VB) [{guid}]";
case CustomDebugInformationKind.DynamicLocalVariables:
return $"{MetadataTokens.GetHeapOffset(debugInfo.Kind):X8} - Dynamic Local Variables (C#) [{guid}]";
case CustomDebugInformationKind.DefaultNamespaces:
return $"{MetadataTokens.GetHeapOffset(debugInfo.Kind):X8} - Default Namespaces (VB) [{guid}]";
case CustomDebugInformationKind.EditAndContinueLocalSlotMap:
return $"{MetadataTokens.GetHeapOffset(debugInfo.Kind):X8} - Edit And Continue Local Slot Map (C# / VB) [{guid}]";
case CustomDebugInformationKind.EditAndContinueLambdaAndClosureMap:
return $"{MetadataTokens.GetHeapOffset(debugInfo.Kind):X8} - Edit And Continue Lambda And Closure Map (C# / VB) [{guid}]";
case CustomDebugInformationKind.EmbeddedSource:
return $"{MetadataTokens.GetHeapOffset(debugInfo.Kind):X8} - Embedded Source (C# / VB) [{guid}]";
case CustomDebugInformationKind.SourceLink:
return $"{MetadataTokens.GetHeapOffset(debugInfo.Kind):X8} - Source Link (C# / VB) [{guid}]";
case CustomDebugInformationKind.MethodSteppingInformation:
return $"{MetadataTokens.GetHeapOffset(debugInfo.Kind):X8} - Method Stepping Information (C# / VB) [{guid}]";
case CustomDebugInformationKind.CompilationOptions:
return $"{MetadataTokens.GetHeapOffset(debugInfo.Kind):X8} - Compilation Options (C# / VB) [{ guid}]";
case CustomDebugInformationKind.CompilationMetadataReferences:
return $"{MetadataTokens.GetHeapOffset(debugInfo.Kind):X8} - Compilation Metadata References (C# / VB) [{ guid}]";
case CustomDebugInformationKind.TupleElementNames:
return $"{MetadataTokens.GetHeapOffset(debugInfo.Kind):X8} - Tuple Element Names (C#) [{ guid}]";
default:
return $"{MetadataTokens.GetHeapOffset(debugInfo.Kind):X8} - Unknown [{guid}]";
}
if (KnownGuids.MethodSteppingInformation == guid)
{
return "Method Stepping Information (C# / VB) [" + guid + "]";
}
return $"Unknown [" + guid + "]";
}
}
@ -156,6 +251,75 @@ namespace ICSharpCode.ILSpy.Metadata @@ -156,6 +251,75 @@ namespace ICSharpCode.ILSpy.Metadata
}
}
object rowDetails;
public object RowDetails {
get {
if (rowDetails != null)
return rowDetails;
if (debugInfo.Value.IsNil)
return null;
var reader = metadata.GetBlobReader(debugInfo.Value);
ArrayList list;
switch (kind)
{
case CustomDebugInformationKind.None:
return null;
case CustomDebugInformationKind.StateMachineHoistedLocalScopes:
list = new ArrayList();
while (reader.RemainingBytes > 0)
{
uint offset = reader.ReadUInt32();
uint length = reader.ReadUInt32();
list.Add(new { StartOffset = offset, Length = length });
}
return rowDetails = list;
case CustomDebugInformationKind.SourceLink:
return reader.ReadUTF8(reader.RemainingBytes);
case CustomDebugInformationKind.CompilationOptions:
list = new ArrayList();
while (reader.RemainingBytes > 0)
{
string name = reader.ReadUTF8StringNullTerminated();
string value = reader.ReadUTF8StringNullTerminated();
list.Add(new { Name = name, Value = value });
}
return rowDetails = list;
case CustomDebugInformationKind.CompilationMetadataReferences:
list = new ArrayList();
while (reader.RemainingBytes > 0)
{
string fileName = reader.ReadUTF8StringNullTerminated();
string aliases = reader.ReadUTF8StringNullTerminated();
byte flags = reader.ReadByte();
uint timestamp = reader.ReadUInt32();
uint fileSize = reader.ReadUInt32();
Guid guid = reader.ReadGuid();
list.Add(new { FileName = fileName, Aliases = aliases, Flags = flags, Timestamp = timestamp, FileSize = fileSize, Guid = guid });
}
return rowDetails = list;
case CustomDebugInformationKind.TupleElementNames:
list = new ArrayList();
while (reader.RemainingBytes > 0)
{
list.Add(new { ElementName = reader.ReadUTF8StringNullTerminated() });
}
return rowDetails = list;
default:
return reader.ToHexString();
}
}
}
public CustomDebugInformationEntry(PEFile module, MetadataReader metadata, bool isEmbedded, CustomDebugInformationHandle handle)
{
this.offset = isEmbedded ? null : (int?)metadata.GetTableMetadataOffset(TableIndex.CustomDebugInformation)
@ -164,6 +328,8 @@ namespace ICSharpCode.ILSpy.Metadata @@ -164,6 +328,8 @@ namespace ICSharpCode.ILSpy.Metadata
this.metadata = metadata;
this.handle = handle;
this.debugInfo = metadata.GetCustomDebugInformation(handle);
this.rowDetails = null;
this.kind = GetKind(metadata, debugInfo.Kind);
}
}

2
ILSpy/Metadata/DebugTables/LocalScopeTableTreeNode.cs

@ -108,10 +108,8 @@ namespace ICSharpCode.ILSpy.Metadata @@ -108,10 +108,8 @@ namespace ICSharpCode.ILSpy.Metadata
[StringFormat("X8")]
public int ConstantList => MetadataTokens.GetToken(localScope.GetLocalConstants().FirstOrDefault());
[StringFormat("X8")]
public int StartOffset => localScope.StartOffset;
[StringFormat("X8")]
public int Length => localScope.Length;
public LocalScopeEntry(PEFile module, MetadataReader metadata, bool isEmbedded, LocalScopeHandle handle)

20
ILSpy/Metadata/Helpers.cs

@ -62,8 +62,7 @@ namespace ICSharpCode.ILSpy.Metadata @@ -62,8 +62,7 @@ namespace ICSharpCode.ILSpy.Metadata
SelectionMode = DataGridSelectionMode.Single,
SelectionUnit = DataGridSelectionUnit.FullRow,
SelectedTreeNode = selectedNode,
VerticalContentAlignment = VerticalAlignment.Center,
CellStyle = (Style)MetadataTableViews.Instance["DataGridCellStyle"]
CellStyle = (Style)MetadataTableViews.Instance["DataGridCellStyle"],
};
ContextMenuProvider.Add(view);
DataGridFilter.SetIsAutoFilterEnabled(view, true);
@ -83,13 +82,13 @@ namespace ICSharpCode.ILSpy.Metadata @@ -83,13 +82,13 @@ namespace ICSharpCode.ILSpy.Metadata
return view;
}
private static void View_AutoGeneratedColumns(object sender, EventArgs e)
internal static void View_AutoGeneratedColumns(object sender, EventArgs e)
{
((DataGrid)sender).AutoGeneratedColumns -= View_AutoGeneratedColumns;
((DataGrid)sender).AutoGeneratingColumn -= View_AutoGeneratingColumn;
}
private static void View_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
internal static void View_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
var binding = new Binding(e.PropertyName) { Mode = BindingMode.OneWay };
e.Column = new DataGridTextColumn() {
@ -105,9 +104,14 @@ namespace ICSharpCode.ILSpy.Metadata @@ -105,9 +104,14 @@ namespace ICSharpCode.ILSpy.Metadata
case "Token":
case "Offset":
case "RVA":
case "StartOffset":
case "Length":
binding.StringFormat = "X8";
e.Column.SetTemplate((ControlTemplate)MetadataTableViews.Instance["HexFilter"]);
break;
case "RowDetails":
e.Cancel = true;
break;
default:
e.Cancel = e.PropertyName.Contains("Tooltip");
if (!e.Cancel)
@ -217,6 +221,14 @@ namespace ICSharpCode.ILSpy.Metadata @@ -217,6 +221,14 @@ namespace ICSharpCode.ILSpy.Metadata
throw new NotImplementedException();
}
}
public static string ReadUTF8StringNullTerminated(this ref BlobReader reader)
{
int length = reader.IndexOf(0);
string s = reader.ReadUTF8(length);
reader.ReadByte();
return s;
}
}
class StringFormatAttribute : Attribute

21
ILSpy/Metadata/MetadataTableViews.xaml

@ -40,7 +40,7 @@ @@ -40,7 +40,7 @@
Text="{Binding Path=Filter, UpdateSourceTrigger=PropertyChanged}" />
</Grid>
</ControlTemplate>
<ControlTemplate x:Key="HexFilter">
<local:HexFilterControl Filter="{Binding Path=Filter, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=dgx:DataGridFilterColumnControl}}" />
</ControlTemplate>
@ -98,4 +98,23 @@ @@ -98,4 +98,23 @@
</Style>
<local:ByteWidthConverter x:Key="byteWidthConverter" />
<DataTemplate x:Key="CustomDebugInformationDetailsDataGrid">
<DataGrid ItemsSource="{Binding RowDetails, Mode=OneWay}" GridLinesVisibility="None" CanUserAddRows="False"
CanUserDeleteRows="False" CanUserReorderColumns="False" RowHeaderWidth="0" EnableColumnVirtualization="True"
EnableRowVirtualization="True" RowHeight="20" IsReadOnly="True" SelectionMode="Single" SelectionUnit="FullRow"
AutoGenerateColumns="True" VerticalContentAlignment="Center" AutoGeneratedColumns="DataGrid_AutoGeneratedColumns" AutoGeneratingColumn="DataGrid_AutoGeneratingColumn"
CellStyle="{StaticResource DataGridCellStyle}" MaxHeight="250">
</DataGrid>
</DataTemplate>
<DataTemplate x:Key="CustomDebugInformationDetailsTextBlob">
<Grid MinWidth="800" MaxWidth="800" HorizontalAlignment="Left">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBox IsReadOnly="True" TextWrapping="Wrap" IsReadOnlyCaretVisible="True" Text="{Binding RowDetails, Mode=OneWay}"
MinLines="10" MaxLines="25" />
</Grid>
</DataTemplate>
</ResourceDictionary>

10
ILSpy/Metadata/MetadataTableViews.xaml.cs

@ -36,5 +36,15 @@ namespace ICSharpCode.ILSpy.Metadata @@ -36,5 +36,15 @@ namespace ICSharpCode.ILSpy.Metadata
return instance;
}
}
private void DataGrid_AutoGeneratedColumns(object sender, EventArgs e)
{
Helpers.View_AutoGeneratedColumns(sender, e);
}
private void DataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
Helpers.View_AutoGeneratingColumn(sender, e);
}
}
}

Loading…
Cancel
Save