Browse Source

Merge pull request #2043 from edkazcarlson/master

Added UnwindInfo as an optional printout
pull/2046/head
Siegfried Pammer 5 years ago committed by GitHub
parent
commit
c0ce62e2d1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 127
      ILSpy.ReadyToRun/ReadyToRunLanguage.cs
  2. 23
      ILSpy.ReadyToRun/ReadyToRunOptionPage.xaml
  3. 16
      ILSpy.ReadyToRun/ReadyToRunOptionPage.xaml.cs
  4. 23
      ILSpy.ReadyToRun/ReadyToRunOptions.cs

127
ILSpy.ReadyToRun/ReadyToRunLanguage.cs

@ -33,8 +33,8 @@ using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Solution; using ICSharpCode.Decompiler.Solution;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.TextView;
using ILCompiler.Reflection.ReadyToRun; using ILCompiler.Reflection.ReadyToRun;
using ILCompiler.Reflection.ReadyToRun.Amd64;
namespace ICSharpCode.ILSpy.ReadyToRun namespace ICSharpCode.ILSpy.ReadyToRun
{ {
@ -103,15 +103,53 @@ namespace ICSharpCode.ILSpy.ReadyToRun
output.WriteLine("; " + comment); output.WriteLine("; " + comment);
} }
private Dictionary<ulong, UnwindCode> WriteUnwindInfo(RuntimeFunction runtimeFunction, ITextOutput output)
{
Dictionary<ulong, UnwindCode> unwindCodes = new Dictionary<ulong, UnwindCode>();
if (runtimeFunction.UnwindInfo is UnwindInfo amd64UnwindInfo) {
string parsedFlags = "";
if ((amd64UnwindInfo.Flags & (int)UnwindFlags.UNW_FLAG_EHANDLER) != 0) {
parsedFlags += " EHANDLER";
}
if ((amd64UnwindInfo.Flags & (int)UnwindFlags.UNW_FLAG_UHANDLER) != 0) {
parsedFlags += " UHANDLER";
}
if ((amd64UnwindInfo.Flags & (int)UnwindFlags.UNW_FLAG_CHAININFO) != 0) {
parsedFlags += " CHAININFO";
}
if (parsedFlags.Length == 0) {
parsedFlags = " NHANDLER";
}
WriteCommentLine(output, $"UnwindInfo:");
WriteCommentLine(output, $"Version: {amd64UnwindInfo.Version}");
WriteCommentLine(output, $"Flags: 0x{amd64UnwindInfo.Flags:X2}{parsedFlags}");
WriteCommentLine(output, $"FrameRegister: {((amd64UnwindInfo.FrameRegister == 0) ? "none" : amd64UnwindInfo.FrameRegister.ToString())}");
for (int unwindCodeIndex = 0; unwindCodeIndex < amd64UnwindInfo.CountOfUnwindCodes; unwindCodeIndex++) {
unwindCodes.Add((ulong)(amd64UnwindInfo.UnwindCodeArray[unwindCodeIndex].CodeOffset), amd64UnwindInfo.UnwindCodeArray[unwindCodeIndex]);
}
}
return unwindCodes;
}
private void Disassemble(PEFile currentFile, ITextOutput output, ReadyToRunReader reader, ReadyToRunMethod readyToRunMethod, RuntimeFunction runtimeFunction, int bitness, ulong address, bool showMetadataTokens, bool showMetadataTokensInBase10) private void Disassemble(PEFile currentFile, ITextOutput output, ReadyToRunReader reader, ReadyToRunMethod readyToRunMethod, RuntimeFunction runtimeFunction, int bitness, ulong address, bool showMetadataTokens, bool showMetadataTokensInBase10)
{ {
WriteCommentLine(output, readyToRunMethod.SignatureString); WriteCommentLine(output, readyToRunMethod.SignatureString);
Dictionary<ulong, UnwindCode> unwindInfo = null;
if (ReadyToRunOptions.GetIsShowUnwindInfo(null) && bitness == 64) {
unwindInfo = WriteUnwindInfo(runtimeFunction, output);
}
byte[] codeBytes = new byte[runtimeFunction.Size]; byte[] codeBytes = new byte[runtimeFunction.Size];
for (int i = 0; i < runtimeFunction.Size; i++) { for (int i = 0; i < runtimeFunction.Size; i++) {
codeBytes[i] = reader.Image[reader.GetOffset(runtimeFunction.StartAddress) + i]; codeBytes[i] = reader.Image[reader.GetOffset(runtimeFunction.StartAddress) + i];
} }
// TODO: Decorate the disassembly with Unwind, GC and debug info // TODO: Decorate the disassembly with GC and debug info
var codeReader = new ByteArrayCodeReader(codeBytes); var codeReader = new ByteArrayCodeReader(codeBytes);
var decoder = Decoder.Create(bitness, codeReader); var decoder = Decoder.Create(bitness, codeReader);
decoder.IP = address; decoder.IP = address;
@ -133,6 +171,7 @@ namespace ICSharpCode.ILSpy.ReadyToRun
formatter.Options.DigitSeparator = "`"; formatter.Options.DigitSeparator = "`";
formatter.Options.FirstOperandCharIndex = 10; formatter.Options.FirstOperandCharIndex = 10;
var tempOutput = new StringOutput(); var tempOutput = new StringOutput();
ulong baseInstrIP = instructions[0].IP;
foreach (var instr in instructions) { foreach (var instr in instructions) {
int byteBaseIndex = (int)(instr.IP - address); int byteBaseIndex = (int)(instr.IP - address);
if (runtimeFunction.DebugInfo != null) { if (runtimeFunction.DebugInfo != null) {
@ -159,43 +198,59 @@ namespace ICSharpCode.ILSpy.ReadyToRun
output.Write(" "); output.Write(" ");
output.Write(" "); output.Write(" ");
output.Write(tempOutput.ToStringAndReset()); output.Write(tempOutput.ToStringAndReset());
int importCellAddress = (int)instr.IPRelativeMemoryAddress; DecorateUnwindInfo(output, unwindInfo, baseInstrIP, instr);
if (instr.IsCallNearIndirect && reader.ImportCellNames.ContainsKey(importCellAddress)) { DecorateCallSite(currentFile, output, reader, showMetadataTokens, showMetadataTokensInBase10, instr);
output.Write(" ; "); }
ReadyToRunSignature signature = reader.ImportSignatures[(int)instr.IPRelativeMemoryAddress]; output.WriteLine();
switch(signature) { }
case MethodDefEntrySignature methodDefSignature:
var methodDefToken = MetadataTokens.EntityHandle(unchecked((int)methodDefSignature.MethodDefToken)); private static void DecorateUnwindInfo(ITextOutput output, Dictionary<ulong, UnwindCode> unwindInfo, ulong baseInstrIP, Instruction instr)
if (showMetadataTokens) { {
if (showMetadataTokensInBase10) { ulong nextInstructionOffset = instr.NextIP - baseInstrIP;
output.WriteReference(currentFile, methodDefToken, $"({MetadataTokens.GetToken(methodDefToken)}) ", "metadata"); if (unwindInfo != null && unwindInfo.ContainsKey(nextInstructionOffset)) {
} else { UnwindCode unwindCode = unwindInfo[nextInstructionOffset];
output.WriteReference(currentFile, methodDefToken, $"({MetadataTokens.GetToken(methodDefToken):X8}) ", "metadata"); output.Write($" ; {unwindCode.UnwindOp}({unwindCode.OpInfoStr})");
} }
}
private static void DecorateCallSite(PEFile currentFile, ITextOutput output, ReadyToRunReader reader, bool showMetadataTokens, bool showMetadataTokensInBase10, Instruction instr)
{
int importCellAddress = (int)instr.IPRelativeMemoryAddress;
if (instr.IsCallNearIndirect && reader.ImportCellNames.ContainsKey(importCellAddress)) {
output.Write(" ; ");
ReadyToRunSignature signature = reader.ImportSignatures[(int)instr.IPRelativeMemoryAddress];
switch (signature) {
case MethodDefEntrySignature methodDefSignature:
var methodDefToken = MetadataTokens.EntityHandle(unchecked((int)methodDefSignature.MethodDefToken));
if (showMetadataTokens) {
if (showMetadataTokensInBase10) {
output.WriteReference(currentFile, methodDefToken, $"({MetadataTokens.GetToken(methodDefToken)}) ", "metadata");
} else {
output.WriteReference(currentFile, methodDefToken, $"({MetadataTokens.GetToken(methodDefToken):X8}) ", "metadata");
} }
methodDefToken.WriteTo(currentFile, output, Decompiler.Metadata.GenericContext.Empty); }
break; methodDefToken.WriteTo(currentFile, output, Decompiler.Metadata.GenericContext.Empty);
case MethodRefEntrySignature methodRefSignature: break;
var methodRefToken = MetadataTokens.EntityHandle(unchecked((int)methodRefSignature.MethodRefToken)); case MethodRefEntrySignature methodRefSignature:
if (showMetadataTokens) { var methodRefToken = MetadataTokens.EntityHandle(unchecked((int)methodRefSignature.MethodRefToken));
if (showMetadataTokensInBase10) { if (showMetadataTokens) {
output.WriteReference(currentFile, methodRefToken, $"({MetadataTokens.GetToken(methodRefToken)}) ", "metadata"); if (showMetadataTokensInBase10) {
} else { output.WriteReference(currentFile, methodRefToken, $"({MetadataTokens.GetToken(methodRefToken)}) ", "metadata");
output.WriteReference(currentFile, methodRefToken, $"({MetadataTokens.GetToken(methodRefToken):X8}) ", "metadata"); } else {
} output.WriteReference(currentFile, methodRefToken, $"({MetadataTokens.GetToken(methodRefToken):X8}) ", "metadata");
} }
methodRefToken.WriteTo(currentFile, output, Decompiler.Metadata.GenericContext.Empty); }
break; methodRefToken.WriteTo(currentFile, output, Decompiler.Metadata.GenericContext.Empty);
default: break;
output.WriteLine(reader.ImportCellNames[importCellAddress]); default:
break; output.WriteLine(reader.ImportCellNames[importCellAddress]);
} break;
output.WriteLine();
} else {
output.WriteLine();
} }
output.WriteLine();
} else {
output.WriteLine();
} }
output.WriteLine();
} }
public override RichText GetRichTextTooltip(IEntity entity) public override RichText GetRichTextTooltip(IEntity entity)
@ -258,4 +313,4 @@ namespace ICSharpCode.ILSpy.ReadyToRun
public Dictionary<EntityHandle, ReadyToRunMethod[]> methodMap; public Dictionary<EntityHandle, ReadyToRunMethod[]> methodMap;
} }
} }
} }

23
ILSpy.ReadyToRun/ReadyToRunOptionPage.xaml

@ -1,10 +1,21 @@
<UserControl x:Class="ICSharpCode.ILSpy.ReadyToRun.ReadyToRunOptionPage" <UserControl x:Class="ICSharpCode.ILSpy.ReadyToRun.ReadyToRunOptionPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel> <Grid>
<StackPanel Orientation="Horizontal"> <Grid.ColumnDefinitions>
<TextBlock>Disassembly Format</TextBlock> <ColumnDefinition />
<ComboBox ItemsSource="{Binding DisassemblyFormats}" SelectedItem="{Binding DisassemblyFormat}"/> <ColumnDefinition />
</StackPanel> </Grid.ColumnDefinitions>
</StackPanel> <Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Margin="3">Disassembly Format</TextBlock>
<ComboBox Grid.Column="1" Margin="3" ItemsSource="{Binding DisassemblyFormats}" SelectedItem="{Binding DisassemblyFormat}" />
<TextBlock Grid.Row="1" Margin="3">Show Unwind Info</TextBlock>
<CheckBox Grid.Row="1" Grid.Column="1" Margin="3" IsChecked="{Binding IsShowUnwindInfo}" />
<TextBlock Grid.Row="2" Margin="3">Show Debug Info</TextBlock>
<CheckBox Grid.Row="2" Grid.Column="1" Margin="3" IsChecked="{Binding DebugIsChecked}" />
</Grid>
</UserControl> </UserControl>

16
ILSpy.ReadyToRun/ReadyToRunOptionPage.xaml.cs

@ -35,6 +35,8 @@ namespace ICSharpCode.ILSpy.ReadyToRun
{ {
Options s = new Options(); Options s = new Options();
s.DisassemblyFormat = ReadyToRunOptions.GetDisassemblyFormat(settings); s.DisassemblyFormat = ReadyToRunOptions.GetDisassemblyFormat(settings);
s.IsShowUnwindInfo = ReadyToRunOptions.GetIsShowUnwindInfo(settings);
this.DataContext = s; this.DataContext = s;
} }
@ -46,7 +48,7 @@ namespace ICSharpCode.ILSpy.ReadyToRun
public void Save(XElement root) public void Save(XElement root)
{ {
Options s = (Options)this.DataContext; Options s = (Options)this.DataContext;
ReadyToRunOptions.SetDisassemblyFormat(root, s.DisassemblyFormat); ReadyToRunOptions.SetDisassemblyOptions(root, s.DisassemblyFormat, s.IsShowUnwindInfo);
} }
} }
@ -58,6 +60,18 @@ namespace ICSharpCode.ILSpy.ReadyToRun
} }
} }
private bool isShowUnwindInfo;
public bool IsShowUnwindInfo {
get {
return isShowUnwindInfo;
}
set {
isShowUnwindInfo = value;
OnPropertyChanged(nameof(IsShowUnwindInfo));
}
}
private string disassemblyFormat; private string disassemblyFormat;
public string DisassemblyFormat { public string DisassemblyFormat {

23
ILSpy.ReadyToRun/ReadyToRunOptions.cs

@ -42,11 +42,27 @@ namespace ICSharpCode.ILSpy.ReadyToRun
} }
} }
public static void SetDisassemblyFormat(XElement root, string disassemblyFormat) public static bool GetIsShowUnwindInfo(ILSpySettings settings)
{
if (settings == null) {
settings = ILSpySettings.Load();
}
XElement e = settings[ns + "ReadyToRunOptions"];
XAttribute a = e.Attribute("IsShowUnwindInfo");
if (a == null) {
return false;
} else {
return (bool)a;
}
}
public static void SetDisassemblyOptions(XElement root, string disassemblyFormat, bool IsShowUnwindInfo)
{ {
XElement section = new XElement(ns + "ReadyToRunOptions"); XElement section = new XElement(ns + "ReadyToRunOptions");
section.SetAttributeValue("DisassemblyFormat", disassemblyFormat); section.SetAttributeValue("DisassemblyFormat", disassemblyFormat);
section.SetAttributeValue("IsShowUnwindInfo", IsShowUnwindInfo);
XElement existingElement = root.Element(ns + "ReadyToRunOptions"); XElement existingElement = root.Element(ns + "ReadyToRunOptions");
if (existingElement != null) { if (existingElement != null) {
existingElement.ReplaceWith(section); existingElement.ReplaceWith(section);
@ -54,5 +70,8 @@ namespace ICSharpCode.ILSpy.ReadyToRun
root.Add(section); root.Add(section);
} }
} }
} }
} }

Loading…
Cancel
Save