diff --git a/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
index b2c176ae0..3d085f25d 100644
--- a/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
+++ b/ICSharpCode.Decompiler/Disassembler/MethodBodyDisassembler.cs
@@ -58,6 +58,11 @@ namespace ICSharpCode.Decompiler.Disassembler
///
public bool ShowMetadataTokensInBase10 { get; set; }
+ ///
+ /// Show raw RVA offset and bytes before each instruction.
+ ///
+ public bool ShowRawRVAOffsetAndBytes { get; set; }
+
///
/// Optional provider for sequence points.
///
@@ -128,14 +133,14 @@ namespace ICSharpCode.Decompiler.Disassembler
blob.Reset();
HashSet branchTargets = GetBranchTargets(blob);
blob.Reset();
- WriteStructureBody(new ILStructure(module, handle, genericContext, body), branchTargets, ref blob);
+ WriteStructureBody(new ILStructure(module, handle, genericContext, body), branchTargets, ref blob, methodDefinition.RelativeVirtualAddress + headerSize);
}
else
{
while (blob.RemainingBytes > 0)
{
cancellationToken.ThrowIfCancellationRequested();
- WriteInstruction(output, metadata, handle, ref blob);
+ WriteInstruction(output, metadata, handle, ref blob, methodDefinition.RelativeVirtualAddress);
}
WriteExceptionHandlers(module, handle, body);
}
@@ -281,7 +286,7 @@ namespace ICSharpCode.Decompiler.Disassembler
output.Indent();
}
- void WriteStructureBody(ILStructure s, HashSet branchTargets, ref BlobReader body)
+ void WriteStructureBody(ILStructure s, HashSet branchTargets, ref BlobReader body, int methodRva)
{
bool isFirstInstructionInStructure = true;
bool prevInstructionWasBranch = false;
@@ -294,7 +299,7 @@ namespace ICSharpCode.Decompiler.Disassembler
{
ILStructure child = s.Children[childIndex++];
WriteStructureHeader(child);
- WriteStructureBody(child, branchTargets, ref body);
+ WriteStructureBody(child, branchTargets, ref body, methodRva);
WriteStructureFooter(child);
}
else
@@ -305,7 +310,7 @@ namespace ICSharpCode.Decompiler.Disassembler
}
var currentOpCode = ILParser.DecodeOpCode(ref body);
body.Offset = offset; // reset IL stream
- WriteInstruction(output, metadata, s.MethodHandle, ref body);
+ WriteInstruction(output, metadata, s.MethodHandle, ref body, methodRva);
prevInstructionWasBranch = currentOpCode.IsBranch()
|| currentOpCode.IsReturn()
|| currentOpCode == ILOpCode.Throw
@@ -338,7 +343,7 @@ namespace ICSharpCode.Decompiler.Disassembler
}
}
- protected virtual void WriteInstruction(ITextOutput output, MetadataReader metadata, MethodDefinitionHandle methodDefinition, ref BlobReader blob)
+ protected virtual void WriteInstruction(ITextOutput output, MetadataReader metadata, MethodDefinitionHandle methodHandle, ref BlobReader blob, int methodRva)
{
int offset = blob.Offset;
if (ShowSequencePoints && nextSequencePointIndex < sequencePoints?.Count)
@@ -363,10 +368,11 @@ namespace ICSharpCode.Decompiler.Disassembler
}
}
ILOpCode opCode = ILParser.DecodeOpCode(ref blob);
- output.WriteLocalReference(DisassemblerHelpers.OffsetToString(offset), offset, isDefinition: true);
- output.Write(": ");
if (opCode.IsDefined())
{
+ WriteRVA(blob, offset + methodRva, opCode);
+ output.WriteLocalReference(DisassemblerHelpers.OffsetToString(offset), offset, isDefinition: true);
+ output.Write(": ");
WriteOpCode(opCode);
switch (opCode.GetOperandType())
{
@@ -469,12 +475,40 @@ namespace ICSharpCode.Decompiler.Disassembler
WriteMetadataToken(userString, metadataToken, spaceBefore: true);
break;
case OperandType.Switch:
+ var tmp = blob;
int[] targets = ILParser.DecodeSwitchTargets(ref blob);
- output.Write(" (");
+ if (ShowRawRVAOffsetAndBytes)
+ {
+ output.WriteLine(" (");
+ }
+ else
+ {
+ output.Write(" (");
+ }
+ tmp.ReadInt32();
for (int i = 0; i < targets.Length; i++)
{
if (i > 0)
- output.Write(", ");
+ {
+ if (ShowRawRVAOffsetAndBytes)
+ {
+ output.WriteLine(",");
+ }
+ else
+ {
+ output.Write(", ");
+ }
+ }
+ if (ShowRawRVAOffsetAndBytes)
+ {
+ output.Write("/* ");
+ output.Write($"{tmp.ReadByte():X2}{tmp.ReadByte():X2}{tmp.ReadByte():X2}{tmp.ReadByte():X2}");
+ output.Write(" */ ");
+ }
+ if (ShowRawRVAOffsetAndBytes)
+ {
+ output.Write(" ");
+ }
output.WriteLocalReference($"IL_{targets[i]:x4}", targets[i]);
}
output.Write(")");
@@ -484,11 +518,11 @@ namespace ICSharpCode.Decompiler.Disassembler
int index = blob.ReadUInt16();
if (opCode == ILOpCode.Ldloc || opCode == ILOpCode.Ldloca || opCode == ILOpCode.Stloc)
{
- DisassemblerHelpers.WriteVariableReference(output, metadata, methodDefinition, index);
+ DisassemblerHelpers.WriteVariableReference(output, metadata, methodHandle, index);
}
else
{
- DisassemblerHelpers.WriteParameterReference(output, metadata, methodDefinition, index);
+ DisassemblerHelpers.WriteParameterReference(output, metadata, methodHandle, index);
}
break;
case OperandType.ShortVariable:
@@ -496,11 +530,11 @@ namespace ICSharpCode.Decompiler.Disassembler
index = blob.ReadByte();
if (opCode == ILOpCode.Ldloc_s || opCode == ILOpCode.Ldloca_s || opCode == ILOpCode.Stloc_s)
{
- DisassemblerHelpers.WriteVariableReference(output, metadata, methodDefinition, index);
+ DisassemblerHelpers.WriteVariableReference(output, metadata, methodHandle, index);
}
else
{
- DisassemblerHelpers.WriteParameterReference(output, metadata, methodDefinition, index);
+ DisassemblerHelpers.WriteParameterReference(output, metadata, methodHandle, index);
}
break;
}
@@ -510,8 +544,22 @@ namespace ICSharpCode.Decompiler.Disassembler
ushort opCodeValue = (ushort)opCode;
if (opCodeValue > 0xFF)
{
+ if (ShowRawRVAOffsetAndBytes)
+ {
+ output.Write("/* ");
+ output.Write($"0x{offset + methodRva:X8} {(ushort)opCode >> 8:X2}");
+ output.Write(" */ ");
+ }
+ output.WriteLocalReference(DisassemblerHelpers.OffsetToString(offset), offset, isDefinition: true);
+ output.Write(": ");
// split 16-bit value into two emitbyte directives
output.WriteLine($".emitbyte 0x{(byte)(opCodeValue >> 8):x}");
+ if (ShowRawRVAOffsetAndBytes)
+ {
+ output.Write("/* ");
+ output.Write($"0x{offset + methodRva + 1:X8} {(ushort)opCode & 0xFF:X2}");
+ output.Write(" */ ");
+ }
// add label
output.WriteLocalReference(DisassemblerHelpers.OffsetToString(offset + 1), offset + 1, isDefinition: true);
output.Write(": ");
@@ -519,12 +567,49 @@ namespace ICSharpCode.Decompiler.Disassembler
}
else
{
+ if (ShowRawRVAOffsetAndBytes)
+ {
+ output.Write("/* ");
+ output.Write($"0x{offset + methodRva:X8} {(ushort)opCode & 0xFF:X2}");
+ output.Write(" */ ");
+ }
+ output.WriteLocalReference(DisassemblerHelpers.OffsetToString(offset), offset, isDefinition: true);
+ output.Write(": ");
output.Write($".emitbyte 0x{(byte)opCodeValue:x}");
}
}
output.WriteLine();
}
+ void WriteRVA(BlobReader blob, int offset, ILOpCode opCode)
+ {
+ if (ShowRawRVAOffsetAndBytes)
+ {
+ output.Write("/* ");
+ var tmp = blob;
+ if (opCode == ILOpCode.Switch)
+ {
+ tmp.ReadInt32();
+ }
+ else
+ {
+ ILParser.SkipOperand(ref tmp, opCode);
+ }
+ output.Write($"0x{offset:X8} {(ushort)opCode:X2}");
+ int appendSpaces = (ushort)opCode > 0xFF ? 14 : 16;
+ while (blob.Offset < tmp.Offset)
+ {
+ output.Write($"{blob.ReadByte():X2}");
+ appendSpaces -= 2;
+ }
+ if (appendSpaces > 0)
+ {
+ output.Write(new string(' ', appendSpaces));
+ }
+ output.Write(" */ ");
+ }
+ }
+
private void WriteOpCode(ILOpCode opCode)
{
var opCodeInfo = new OpCodeInfo(opCode, opCode.GetDisplayName());
diff --git a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
index 861ba7fb2..67cd3ee9b 100644
--- a/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
+++ b/ICSharpCode.Decompiler/Disassembler/ReflectionDisassembler.cs
@@ -61,6 +61,11 @@ namespace ICSharpCode.Decompiler.Disassembler
set => methodBodyDisassembler.ShowMetadataTokensInBase10 = value;
}
+ public bool ShowRawRVAOffsetAndBytes {
+ get => methodBodyDisassembler.ShowRawRVAOffsetAndBytes;
+ set => methodBodyDisassembler.ShowRawRVAOffsetAndBytes = value;
+ }
+
public IDebugInfoProvider DebugInfo {
get => methodBodyDisassembler.DebugInfo;
set => methodBodyDisassembler.DebugInfo = value;
diff --git a/ILSpy/Languages/CSharpILMixedLanguage.cs b/ILSpy/Languages/CSharpILMixedLanguage.cs
index 5bea5a8a3..2fa6a32f8 100644
--- a/ILSpy/Languages/CSharpILMixedLanguage.cs
+++ b/ILSpy/Languages/CSharpILMixedLanguage.cs
@@ -56,6 +56,7 @@ namespace ICSharpCode.ILSpy
options.CancellationToken) {
ShowMetadataTokens = Options.DisplaySettingsPanel.CurrentDisplaySettings.ShowMetadataTokens,
ShowMetadataTokensInBase10 = Options.DisplaySettingsPanel.CurrentDisplaySettings.ShowMetadataTokensInBase10,
+ ShowRawRVAOffsetAndBytes = Options.DisplaySettingsPanel.CurrentDisplaySettings.ShowRawOffsetsAndBytesBeforeInstruction,
ExpandMemberDefinitions = options.DecompilerSettings.ExpandMemberDefinitions
};
}
@@ -109,7 +110,7 @@ namespace ICSharpCode.ILSpy
}
}
- protected override void WriteInstruction(ITextOutput output, MetadataReader metadata, MethodDefinitionHandle methodDefinition, ref BlobReader blob)
+ protected override void WriteInstruction(ITextOutput output, MetadataReader metadata, MethodDefinitionHandle methodHandle, ref BlobReader blob, int methodRva)
{
int index = sequencePoints.BinarySearch(blob.Offset, seq => seq.Offset);
if (index >= 0)
@@ -143,7 +144,7 @@ namespace ICSharpCode.ILSpy
highlightingOutput?.EndSpan();
}
}
- base.WriteInstruction(output, metadata, methodDefinition, ref blob);
+ base.WriteInstruction(output, metadata, methodHandle, ref blob, methodRva);
}
HighlightingColor gray = new HighlightingColor { Foreground = new SimpleHighlightingBrush(Colors.DarkGray) };
diff --git a/ILSpy/Languages/ILLanguage.cs b/ILSpy/Languages/ILLanguage.cs
index 9e20cd280..d31068de4 100644
--- a/ILSpy/Languages/ILLanguage.cs
+++ b/ILSpy/Languages/ILLanguage.cs
@@ -61,6 +61,7 @@ namespace ICSharpCode.ILSpy
ShowSequencePoints = options.DecompilerSettings.ShowDebugInfo,
ShowMetadataTokens = Options.DisplaySettingsPanel.CurrentDisplaySettings.ShowMetadataTokens,
ShowMetadataTokensInBase10 = Options.DisplaySettingsPanel.CurrentDisplaySettings.ShowMetadataTokensInBase10,
+ ShowRawRVAOffsetAndBytes = Options.DisplaySettingsPanel.CurrentDisplaySettings.ShowRawOffsetsAndBytesBeforeInstruction,
ExpandMemberDefinitions = options.DecompilerSettings.ExpandMemberDefinitions
};
}
diff --git a/ILSpy/Options/DisplaySettings.cs b/ILSpy/Options/DisplaySettings.cs
index 97f54c8b6..bd5f5bc26 100644
--- a/ILSpy/Options/DisplaySettings.cs
+++ b/ILSpy/Options/DisplaySettings.cs
@@ -286,6 +286,19 @@ namespace ICSharpCode.ILSpy.Options
}
}
+ private bool showRawOffsetsAndBytesBeforeInstruction;
+
+ public bool ShowRawOffsetsAndBytesBeforeInstruction {
+ get { return showRawOffsetsAndBytesBeforeInstruction; }
+ set {
+ if (showRawOffsetsAndBytesBeforeInstruction != value)
+ {
+ showRawOffsetsAndBytesBeforeInstruction = value;
+ OnPropertyChanged();
+ }
+ }
+ }
+
public void CopyValues(DisplaySettings s)
{
this.SelectedFont = s.selectedFont;
@@ -305,6 +318,7 @@ namespace ICSharpCode.ILSpy.Options
this.HighlightMatchingBraces = s.highlightMatchingBraces;
this.HighlightCurrentLine = s.highlightCurrentLine;
this.HideEmptyMetadataTables = s.hideEmptyMetadataTables;
+ this.ShowRawOffsetsAndBytesBeforeInstruction = s.showRawOffsetsAndBytesBeforeInstruction;
this.StyleWindowTitleBar = s.styleWindowTitleBar;
}
}
diff --git a/ILSpy/Options/DisplaySettingsPanel.xaml b/ILSpy/Options/DisplaySettingsPanel.xaml
index 08be65bc4..4d5a665f3 100644
--- a/ILSpy/Options/DisplaySettingsPanel.xaml
+++ b/ILSpy/Options/DisplaySettingsPanel.xaml
@@ -82,6 +82,7 @@
+
diff --git a/ILSpy/Options/DisplaySettingsPanel.xaml.cs b/ILSpy/Options/DisplaySettingsPanel.xaml.cs
index ccfeb4d2d..87d6aa4f3 100644
--- a/ILSpy/Options/DisplaySettingsPanel.xaml.cs
+++ b/ILSpy/Options/DisplaySettingsPanel.xaml.cs
@@ -123,6 +123,7 @@ namespace ICSharpCode.ILSpy.Options
s.HighlightMatchingBraces = (bool?)e.Attribute("HighlightMatchingBraces") ?? true;
s.HighlightCurrentLine = (bool?)e.Attribute("HighlightCurrentLine") ?? false;
s.HideEmptyMetadataTables = (bool?)e.Attribute("HideEmptyMetadataTables") ?? true;
+ s.ShowRawOffsetsAndBytesBeforeInstruction = (bool?)e.Attribute("ShowRawOffsetsAndBytesBeforeInstruction") ?? false;
s.StyleWindowTitleBar = (bool?)e.Attribute("StyleWindowTitleBar") ?? false;
return s;
@@ -150,6 +151,7 @@ namespace ICSharpCode.ILSpy.Options
section.SetAttributeValue("HighlightMatchingBraces", s.HighlightMatchingBraces);
section.SetAttributeValue("HighlightCurrentLine", s.HighlightCurrentLine);
section.SetAttributeValue("HideEmptyMetadataTables", s.HideEmptyMetadataTables);
+ section.SetAttributeValue("ShowRawOffsetsAndBytesBeforeInstruction", s.ShowRawOffsetsAndBytesBeforeInstruction);
section.SetAttributeValue("StyleWindowTitleBar", s.StyleWindowTitleBar);
XElement existingElement = root.Element("DisplaySettings");
diff --git a/ILSpy/Properties/Resources.Designer.cs b/ILSpy/Properties/Resources.Designer.cs
index dde98f9aa..0d803c490 100644
--- a/ILSpy/Properties/Resources.Designer.cs
+++ b/ILSpy/Properties/Resources.Designer.cs
@@ -2417,6 +2417,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
+ ///
+ /// Looks up a localized string similar to Show raw offsets and bytes before each instruction.
+ ///
+ public static string ShowRawOffsetsAndBytesBeforeInstruction {
+ get {
+ return ResourceManager.GetString("ShowRawOffsetsAndBytesBeforeInstruction", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Show state after this step.
///
diff --git a/ILSpy/Properties/Resources.resx b/ILSpy/Properties/Resources.resx
index e00992246..e89e582d7 100644
--- a/ILSpy/Properties/Resources.resx
+++ b/ILSpy/Properties/Resources.resx
@@ -825,6 +825,9 @@ Do you want to continue?
Show only public types and members
+
+ Show raw offsets and bytes before each instruction
+
Show state after this step