201 lines
8.3 KiB
C#
201 lines
8.3 KiB
C#
![]() |
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
|
||
|
//
|
||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
|
||
|
// software and associated documentation files (the "Software"), to deal in the Software
|
||
|
// without restriction, including without limitation the rights to use, copy, modify, merge,
|
||
|
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
|
||
|
// to whom the Software is furnished to do so, subject to the following conditions:
|
||
|
//
|
||
|
// The above copyright notice and this permission notice shall be included in all copies or
|
||
|
// substantial portions of the Software.
|
||
|
//
|
||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||
|
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||
|
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
||
|
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||
|
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||
|
// DEALINGS IN THE SOFTWARE.
|
||
|
|
||
|
using System;
|
||
|
using System.Collections.Generic;
|
||
|
using System.Diagnostics;
|
||
|
using System.Text;
|
||
|
using dnlib.DotNet;
|
||
|
using dnSpy.Contracts.Decompiler;
|
||
|
using dnSpy.Contracts.Decompiler.XmlDoc;
|
||
|
using dnSpy.Contracts.Text;
|
||
|
using dnSpy.Decompiler.IL;
|
||
|
using dnSpy.Decompiler.ILSpy.Core.Settings;
|
||
|
using dnSpy.Decompiler.ILSpy.Core.Text;
|
||
|
using dnSpy.Decompiler.ILSpy.Core.XmlDoc;
|
||
|
using ICSharpCode.Decompiler.Disassembler;
|
||
|
|
||
|
namespace dnSpy.Decompiler.ILSpy.Core.IL {
|
||
|
sealed class DecompilerProvider : IDecompilerProvider {
|
||
|
readonly DecompilerSettingsService decompilerSettingsService;
|
||
|
|
||
|
// Keep the default ctor. It's used by dnSpy.Console.exe
|
||
|
public DecompilerProvider()
|
||
|
: this(DecompilerSettingsService.__Instance_DONT_USE) {
|
||
|
}
|
||
|
|
||
|
public DecompilerProvider(DecompilerSettingsService decompilerSettingsService) {
|
||
|
Debug2.Assert(decompilerSettingsService is not null);
|
||
|
this.decompilerSettingsService = decompilerSettingsService ?? throw new ArgumentNullException(nameof(decompilerSettingsService));
|
||
|
}
|
||
|
|
||
|
public IEnumerable<IDecompiler> Create() {
|
||
|
yield return new ILDecompiler(decompilerSettingsService.ILDecompilerSettings);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// IL language support.
|
||
|
/// </summary>
|
||
|
/// <remarks>
|
||
|
/// Currently comes in two versions:
|
||
|
/// flat IL (detectControlStructure=false) and structured IL (detectControlStructure=true).
|
||
|
/// </remarks>
|
||
|
sealed class ILDecompiler : DecompilerBase {
|
||
|
readonly bool detectControlStructure;
|
||
|
|
||
|
public override DecompilerSettingsBase Settings => langSettings;
|
||
|
readonly ILDecompilerSettings langSettings;
|
||
|
|
||
|
public ILDecompiler(ILDecompilerSettings langSettings)
|
||
|
: this(langSettings, true) {
|
||
|
}
|
||
|
|
||
|
public ILDecompiler(ILDecompilerSettings langSettings, bool detectControlStructure) {
|
||
|
this.langSettings = langSettings;
|
||
|
this.detectControlStructure = detectControlStructure;
|
||
|
}
|
||
|
|
||
|
public override double OrderUI => DecompilerConstants.IL_ILSPY_ORDERUI;
|
||
|
public override string ContentTypeString => ContentTypesInternal.ILILSpy;
|
||
|
public override string GenericNameUI => DecompilerConstants.GENERIC_NAMEUI_IL;
|
||
|
public override string UniqueNameUI => "IL";
|
||
|
public override Guid GenericGuid => DecompilerConstants.LANGUAGE_IL;
|
||
|
public override Guid UniqueGuid => DecompilerConstants.LANGUAGE_IL_ILSPY;
|
||
|
public override string FileExtension => ".il";
|
||
|
|
||
|
ReflectionDisassembler CreateReflectionDisassembler(IDecompilerOutput output, DecompilationContext ctx, IMemberDef member) =>
|
||
|
CreateReflectionDisassembler(output, ctx, member.Module);
|
||
|
|
||
|
ReflectionDisassembler CreateReflectionDisassembler(IDecompilerOutput output, DecompilationContext ctx, ModuleDef ownerModule) {
|
||
|
var disOpts = new DisassemblerOptions(langSettings.Settings.SettingsVersion, ctx.CancellationToken, ownerModule);
|
||
|
if (langSettings.Settings.ShowILComments)
|
||
|
disOpts.GetOpCodeDocumentation = ILLanguageHelper.GetOpCodeDocumentation;
|
||
|
var sb = new StringBuilder();
|
||
|
if (langSettings.Settings.ShowXmlDocumentation)
|
||
|
disOpts.GetXmlDocComments = a => GetXmlDocComments(a, sb);
|
||
|
disOpts.CreateInstructionBytesReader = m => InstructionBytesReader.Create(m, ctx.IsBodyModified is not null && ctx.IsBodyModified(m));
|
||
|
disOpts.ShowTokenAndRvaComments = langSettings.Settings.ShowTokenAndRvaComments;
|
||
|
disOpts.ShowILBytes = langSettings.Settings.ShowILBytes;
|
||
|
disOpts.SortMembers = langSettings.Settings.SortMembers;
|
||
|
disOpts.ShowPdbInfo = langSettings.Settings.ShowPdbInfo;
|
||
|
disOpts.MaxStringLength = langSettings.Settings.MaxStringLength;
|
||
|
disOpts.HexadecimalNumbers = langSettings.Settings.HexadecimalNumbers;
|
||
|
return new ReflectionDisassembler(output, detectControlStructure, disOpts);
|
||
|
}
|
||
|
|
||
|
static IEnumerable<string> GetXmlDocComments(IMemberRef mr, StringBuilder sb) {
|
||
|
if (mr is null || mr.Module is null)
|
||
|
yield break;
|
||
|
var xmldoc = XmlDocLoader.LoadDocumentation(mr.Module);
|
||
|
if (xmldoc is null)
|
||
|
yield break;
|
||
|
var doc = xmldoc.GetDocumentation(XmlDocKeyProvider.GetKey(mr, sb));
|
||
|
if (string2.IsNullOrEmpty(doc))
|
||
|
yield break;
|
||
|
|
||
|
foreach (var info in new XmlDocLine(doc)) {
|
||
|
sb.Clear();
|
||
|
if (info is not null) {
|
||
|
sb.Append(' ');
|
||
|
info.Value.WriteTo(sb);
|
||
|
}
|
||
|
yield return sb.ToString();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void Decompile(MethodDef method, IDecompilerOutput output, DecompilationContext ctx) {
|
||
|
var dis = CreateReflectionDisassembler(output, ctx, method);
|
||
|
dis.DisassembleMethod(method, true);
|
||
|
}
|
||
|
|
||
|
public override void Decompile(FieldDef field, IDecompilerOutput output, DecompilationContext ctx) {
|
||
|
var dis = CreateReflectionDisassembler(output, ctx, field);
|
||
|
dis.DisassembleField(field, false);
|
||
|
}
|
||
|
|
||
|
public override void Decompile(PropertyDef property, IDecompilerOutput output, DecompilationContext ctx) {
|
||
|
ReflectionDisassembler rd = CreateReflectionDisassembler(output, ctx, property);
|
||
|
rd.DisassembleProperty(property, addLineSep: true);
|
||
|
if (property.GetMethod is not null) {
|
||
|
output.WriteLine();
|
||
|
rd.DisassembleMethod(property.GetMethod, true);
|
||
|
}
|
||
|
if (property.SetMethod is not null) {
|
||
|
output.WriteLine();
|
||
|
rd.DisassembleMethod(property.SetMethod, true);
|
||
|
}
|
||
|
foreach (var m in property.OtherMethods) {
|
||
|
output.WriteLine();
|
||
|
rd.DisassembleMethod(m, true);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void Decompile(EventDef ev, IDecompilerOutput output, DecompilationContext ctx) {
|
||
|
ReflectionDisassembler rd = CreateReflectionDisassembler(output, ctx, ev);
|
||
|
rd.DisassembleEvent(ev, addLineSep: true);
|
||
|
if (ev.AddMethod is not null) {
|
||
|
output.WriteLine();
|
||
|
rd.DisassembleMethod(ev.AddMethod, true);
|
||
|
}
|
||
|
if (ev.RemoveMethod is not null) {
|
||
|
output.WriteLine();
|
||
|
rd.DisassembleMethod(ev.RemoveMethod, true);
|
||
|
}
|
||
|
foreach (var m in ev.OtherMethods) {
|
||
|
output.WriteLine();
|
||
|
rd.DisassembleMethod(m, true);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
public override void Decompile(TypeDef type, IDecompilerOutput output, DecompilationContext ctx) {
|
||
|
var dis = CreateReflectionDisassembler(output, ctx, type);
|
||
|
dis.DisassembleType(type, true);
|
||
|
}
|
||
|
|
||
|
public override void Decompile(AssemblyDef asm, IDecompilerOutput output, DecompilationContext ctx) {
|
||
|
output.WriteLine("// " + asm.ManifestModule.Location, BoxedTextColor.Comment);
|
||
|
PrintEntryPoint(asm.ManifestModule, output);
|
||
|
output.WriteLine();
|
||
|
|
||
|
ReflectionDisassembler rd = CreateReflectionDisassembler(output, ctx, asm.ManifestModule);
|
||
|
rd.WriteAssemblyHeader(asm);
|
||
|
}
|
||
|
|
||
|
public override void Decompile(ModuleDef mod, IDecompilerOutput output, DecompilationContext ctx) {
|
||
|
output.WriteLine("// " + mod.Location, BoxedTextColor.Comment);
|
||
|
PrintEntryPoint(mod, output);
|
||
|
output.WriteLine();
|
||
|
|
||
|
ReflectionDisassembler rd = CreateReflectionDisassembler(output, ctx, mod);
|
||
|
output.WriteLine();
|
||
|
rd.WriteModuleHeader(mod);
|
||
|
}
|
||
|
|
||
|
protected override void TypeToString(IDecompilerOutput output, ITypeDefOrRef? t, bool includeNamespace, IHasCustomAttribute? attributeProvider = null) =>
|
||
|
t.WriteTo(output, includeNamespace ? ILNameSyntax.TypeName : ILNameSyntax.ShortTypeName);
|
||
|
|
||
|
public override void WriteToolTip(ITextColorWriter output, IMemberRef member, IHasCustomAttribute? typeAttributes) {
|
||
|
if (!(member is ITypeDefOrRef) && ILDecompilerUtils.Write(TextColorWriterToDecompilerOutput.Create(output), member))
|
||
|
return;
|
||
|
|
||
|
base.WriteToolTip(output, member, typeAttributes);
|
||
|
}
|
||
|
}
|
||
|
}
|