Skip to content

Commit

Permalink
Merge pull request icsharpcode#3076 from eduardo-vp/add/gc-info
Browse files Browse the repository at this point in the history
  • Loading branch information
siegfriedpammer authored Sep 9, 2023
2 parents 25e3ca4 + 2b8bf81 commit 0c2e4b1
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 25 deletions.
15 changes: 12 additions & 3 deletions ILSpy.ReadyToRun/Properties/Resources.Designer.cs

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 5 additions & 2 deletions ILSpy.ReadyToRun/Properties/Resources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,10 @@
<data name="ShowDebugInfo" xml:space="preserve">
<value>Show Debug Info</value>
</data>
<data name="ShowUnwindInfo" xml:space="preserve">
<value>Show Unwind Info</value>
<data name="ShowGCInfo" xml:space="preserve">
<value>Show GC Info</value>
</data>
<data name="ShowStackUnwindInfo" xml:space="preserve">
<value>Show Stack Unwind Info</value>
</data>
</root>
7 changes: 5 additions & 2 deletions ILSpy.ReadyToRun/Properties/Resources.zh-Hans.resx
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,10 @@
<data name="ShowDebugInfo" xml:space="preserve">
<value>显示调试信息</value>
</data>
<data name="ShowUnwindInfo" xml:space="preserve">
<value>显示展开信息</value>
<data name="ShowGCInfo" xml:space="preserve">
<value>显示垃圾回收信息</value>
</data>
<data name="ShowStackUnwindInfo" xml:space="preserve">
<value>显示堆栈展开信息</value>
</data>
</root>
66 changes: 51 additions & 15 deletions ILSpy.ReadyToRun/ReadyToRunDisassembler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,26 @@ public ReadyToRunDisassembler(ITextOutput output, ReadyToRunReader reader, Runti

public void Disassemble(PEFile currentFile, int bitness, ulong address, bool showMetadataTokens, bool showMetadataTokensInBase10)
{
// TODO: Decorate the disassembly with GCInfo
ReadyToRunMethod readyToRunMethod = runtimeFunction.Method;
WriteCommentLine(readyToRunMethod.SignatureString);

if (ReadyToRunOptions.GetIsShowGCInfo(null))
{
if (readyToRunMethod.GcInfo != null)
{
string[] lines = readyToRunMethod.GcInfo.ToString().Split(Environment.NewLine);
WriteCommentLine("GC info:");
foreach (string line in lines)
{
WriteCommentLine(line);
}
}
else
{
WriteCommentLine("GC Info is not available for this method");
}
}

Dictionary<ulong, UnwindCode> unwindInfo = null;
if (ReadyToRunOptions.GetIsShowUnwindInfo(null) && bitness == 64)
{
Expand Down Expand Up @@ -96,30 +112,36 @@ public void Disassemble(PEFile currentFile, int bitness, ulong address, bool sho
formatter.Options.FirstOperandCharIndex = 10;
var tempOutput = new StringOutput();
ulong baseInstrIP = instructions[0].IP;

var boundsMap = new Dictionary<uint, uint>();
foreach (var bound in runtimeFunction.DebugInfo.BoundsList)
{
// ignoring the return value assuming the same key is always mapped to the same value in runtimeFunction.DebugInfo.BoundsList
boundsMap.TryAdd(bound.NativeOffset, bound.ILOffset);
}

foreach (var instr in instructions)
{
int byteBaseIndex = (int)(instr.IP - address);
if (isShowDebugInfo && runtimeFunction.DebugInfo != null)
{
foreach (var bound in runtimeFunction.DebugInfo.BoundsList)
if (byteBaseIndex >= 0 && boundsMap.TryGetValue((uint)byteBaseIndex, out uint boundILOffset))
{
if (bound.NativeOffset == byteBaseIndex)
if (boundILOffset == (uint)DebugInfoBoundsType.Prolog)
{
if (bound.ILOffset == (uint)DebugInfoBoundsType.Prolog)
{
WriteCommentLine("Prolog");
}
else if (bound.ILOffset == (uint)DebugInfoBoundsType.Epilog)
{
WriteCommentLine("Epilog");
}
else
{
WriteCommentLine($"IL_{bound.ILOffset:x4}");
}
WriteCommentLine("Prolog");
}
else if (boundILOffset == (uint)DebugInfoBoundsType.Epilog)
{
WriteCommentLine("Epilog");
}
else
{
WriteCommentLine($"IL_{boundILOffset:x4}");
}
}
}
DecorateGCInfo(instr, baseInstrIP, readyToRunMethod.GcInfo);
formatter.Format(instr, tempOutput);
output.Write(instr.IP.ToString("X16"));
output.Write(" ");
Expand All @@ -143,6 +165,20 @@ public void Disassemble(PEFile currentFile, int bitness, ulong address, bool sho
output.WriteLine();
}

private void DecorateGCInfo(Instruction instr, ulong baseInstrIP, BaseGcInfo gcInfo)
{
ulong codeOffset = instr.IP - baseInstrIP;
if (gcInfo != null && gcInfo.Transitions != null && gcInfo.Transitions.TryGetValue((int)codeOffset, out List<BaseGcTransition> transitionsForOffset))
{
// this value comes from a manual count of the spaces used for each instruction in Disassemble()
string indent = new string(' ', 36);
foreach (var transition in transitionsForOffset)
{
WriteCommentLine(indent + transition.ToString());
}
}
}

private void WriteCommentLine(string comment)
{
output.WriteLine("; " + comment);
Expand Down
5 changes: 4 additions & 1 deletion ILSpy.ReadyToRun/ReadyToRunOptionPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,15 @@
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Margin="3" Text="{x:Static properties:Resources.DisassemblyFormat}" />
<ComboBox Grid.Column="1" Margin="3" ItemsSource="{Binding DisassemblyFormats}" SelectedItem="{Binding DisassemblyFormat}" />
<TextBlock Grid.Row="1" Margin="3" Text="{x:Static properties:Resources.ShowUnwindInfo}"/>
<TextBlock Grid.Row="1" Margin="3" Text="{x:Static properties:Resources.ShowStackUnwindInfo}"/>
<CheckBox Grid.Row="1" Grid.Column="1" Margin="3" IsChecked="{Binding IsShowUnwindInfo}" />
<TextBlock Grid.Row="2" Margin="3" Text="{x:Static properties:Resources.ShowDebugInfo}"/>
<CheckBox Grid.Row="2" Grid.Column="1" Margin="3" IsChecked="{Binding IsShowDebugInfo}" />
<TextBlock Grid.Row="3" Margin="3" Text="{x:Static properties:Resources.ShowGCInfo}"/>
<CheckBox Grid.Row="3" Grid.Column="1" Margin="3" IsChecked="{Binding IsShowGCInfo}" />
</Grid>
</UserControl>
15 changes: 14 additions & 1 deletion ILSpy.ReadyToRun/ReadyToRunOptionPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ public void Load(ILSpySettings settings)
s.DisassemblyFormat = ReadyToRunOptions.GetDisassemblyFormat(settings);
s.IsShowUnwindInfo = ReadyToRunOptions.GetIsShowUnwindInfo(settings);
s.IsShowDebugInfo = ReadyToRunOptions.GetIsShowDebugInfo(settings);
s.IsShowGCInfo = ReadyToRunOptions.GetIsShowGCInfo(settings);

this.DataContext = s;
}
Expand All @@ -51,7 +52,7 @@ public void LoadDefaults()
public void Save(XElement root)
{
Options s = (Options)this.DataContext;
ReadyToRunOptions.SetDisassemblyOptions(root, s.DisassemblyFormat, s.IsShowUnwindInfo, s.IsShowDebugInfo);
ReadyToRunOptions.SetDisassemblyOptions(root, s.DisassemblyFormat, s.IsShowUnwindInfo, s.IsShowDebugInfo, s.IsShowGCInfo);
}
}

Expand Down Expand Up @@ -86,6 +87,18 @@ public bool IsShowDebugInfo {
}
}

private bool isShowGCInfo;

public bool IsShowGCInfo {
get {
return isShowGCInfo;
}
set {
isShowGCInfo = value;
OnPropertyChanged(nameof(IsShowGCInfo));
}
}

private string disassemblyFormat;

public string DisassemblyFormat {
Expand Down
22 changes: 21 additions & 1 deletion ILSpy.ReadyToRun/ReadyToRunOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -87,12 +87,32 @@ public static bool GetIsShowDebugInfo(ILSpySettings settings)
}
}

public static void SetDisassemblyOptions(XElement root, string disassemblyFormat, bool isShowUnwindInfo, bool isShowDebugInfo)
public static bool GetIsShowGCInfo(ILSpySettings settings)
{
if (settings == null)
{
settings = ILSpySettings.Load();
}
XElement e = settings[ns + "ReadyToRunOptions"];
XAttribute a = e.Attribute("IsShowGCInfo");

if (a == null)
{
return false;
}
else
{
return (bool)a;
}
}

public static void SetDisassemblyOptions(XElement root, string disassemblyFormat, bool isShowUnwindInfo, bool isShowDebugInfo, bool isShowGCInfo)
{
XElement section = new XElement(ns + "ReadyToRunOptions");
section.SetAttributeValue("DisassemblyFormat", disassemblyFormat);
section.SetAttributeValue("IsShowUnwindInfo", isShowUnwindInfo);
section.SetAttributeValue("IsShowDebugInfo", isShowDebugInfo);
section.SetAttributeValue("IsShowGCInfo", isShowGCInfo);
XElement existingElement = root.Element(ns + "ReadyToRunOptions");
if (existingElement != null)
{
Expand Down

0 comments on commit 0c2e4b1

Please sign in to comment.