|
|
@ -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; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|