mirror of https://github.com/icsharpcode/ILSpy.git
15 changed files with 495 additions and 23 deletions
@ -0,0 +1,71 @@
@@ -0,0 +1,71 @@
|
||||
<?xml version="1.0" encoding="utf-8"?> |
||||
<Project> |
||||
<Import Sdk="Microsoft.NET.Sdk" Project="Sdk.props" /> |
||||
|
||||
<PropertyGroup> |
||||
<TargetFramework>net472</TargetFramework> |
||||
<AssemblyName>ILSpy.ReadyToRun.Plugin</AssemblyName> |
||||
<LangVersion>7.2</LangVersion> |
||||
|
||||
<GenerateAssemblyInfo>False</GenerateAssemblyInfo> |
||||
|
||||
<EnableDefaultItems>false</EnableDefaultItems> |
||||
</PropertyGroup> |
||||
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Debug'"> |
||||
<DebugType>full</DebugType> |
||||
<DebugSymbols>true</DebugSymbols> |
||||
<CheckForOverflowUnderflow>True</CheckForOverflowUnderflow> |
||||
</PropertyGroup> |
||||
|
||||
<PropertyGroup Condition="'$(Configuration)' == 'Release'"> |
||||
<DebugType>pdbonly</DebugType> |
||||
<DebugSymbols>true</DebugSymbols> |
||||
</PropertyGroup> |
||||
|
||||
<PropertyGroup> |
||||
<OutputPath>..\ILSpy\bin\$(Configuration)\</OutputPath> |
||||
</PropertyGroup> |
||||
|
||||
<ItemGroup> |
||||
<ProjectReference Include="..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.csproj"> |
||||
<Private>False</Private> |
||||
</ProjectReference> |
||||
<ProjectReference Include="..\ILSpy\ILSpy.csproj"> |
||||
<Private>False</Private> |
||||
</ProjectReference> |
||||
<ProjectReference Include="..\SharpTreeView\ICSharpCode.TreeView.csproj"> |
||||
<Private>False</Private> |
||||
</ProjectReference> |
||||
<Reference Include="PresentationCore" /> |
||||
<Reference Include="PresentationFramework" /> |
||||
<Reference Include="System.Xaml" /> |
||||
<Reference Include="WindowsBase" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<Compile Include="ReadyToRunLanguage.cs" /> |
||||
<Compile Include="ReadyToRunOptionPage.xaml.cs"> |
||||
<DependentUpon>ReadyToRunOptionPage.xaml</DependentUpon> |
||||
</Compile> |
||||
<Compile Include="ReadyToRunOptions.cs" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<Page Include="ReadyToRunOptionPage.xaml" /> |
||||
</ItemGroup> |
||||
|
||||
<ItemGroup> |
||||
<PackageReference Include="Iced" Version="1.4.0" /> |
||||
<PackageReference Include="ILCompiler.Reflection.ReadyToRun" Version="1.0.2-alpha" /> |
||||
</ItemGroup> |
||||
|
||||
<Import Sdk="Microsoft.NET.Sdk" Project="Sdk.targets" /> |
||||
|
||||
<Target Name="RemoveTransitiveProjectReferences" AfterTargets="IncludeTransitiveProjectReferences"> |
||||
<ItemGroup> |
||||
<ProjectReference Remove="@(_TransitiveProjectReferences)" /> |
||||
</ItemGroup> |
||||
</Target> |
||||
|
||||
</Project> |
@ -0,0 +1,33 @@
@@ -0,0 +1,33 @@
|
||||
#region Using directives
|
||||
|
||||
using System.Reflection; |
||||
using System.Runtime.InteropServices; |
||||
using System.Runtime.CompilerServices; |
||||
|
||||
#endregion
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("ILSpy.ReadyToRun.Plugin")] |
||||
[assembly: AssemblyDescription("")] |
||||
[assembly: AssemblyConfiguration("")] |
||||
[assembly: AssemblyCompany("")] |
||||
[assembly: AssemblyProduct("ILSpy.ReadyToRun.Plugin")] |
||||
[assembly: AssemblyCopyright("Copyright 2011")] |
||||
[assembly: AssemblyTrademark("")] |
||||
[assembly: AssemblyCulture("")] |
||||
|
||||
// This sets the default COM visibility of types in the assembly to invisible.
|
||||
// If you need to expose a type to COM, use [ComVisible(true)] on that type.
|
||||
[assembly: ComVisible(false)] |
||||
|
||||
[assembly: InternalsVisibleTo("ILSpy.ReadyToRun.Tests")] |
||||
|
||||
// The assembly version has following format :
|
||||
//
|
||||
// Major.Minor.Build.Revision
|
||||
//
|
||||
// You can specify all the values or you can use the default the Revision and
|
||||
// Build Numbers by using the '*' as shown below:
|
||||
[assembly: AssemblyVersion("1.0.0.0")] |
@ -0,0 +1,187 @@
@@ -0,0 +1,187 @@
|
||||
// Copyright (c) 2018 Siegfried Pammer
|
||||
//
|
||||
// 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.ComponentModel.Composition; |
||||
using System.Diagnostics; |
||||
using System.Reflection.Metadata; |
||||
using System.Reflection.PortableExecutable; |
||||
using System.Runtime.CompilerServices; |
||||
using Iced.Intel; |
||||
using ICSharpCode.Decompiler; |
||||
using ICSharpCode.Decompiler.Metadata; |
||||
using ICSharpCode.Decompiler.Solution; |
||||
using ICSharpCode.Decompiler.TypeSystem; |
||||
using ILCompiler.Reflection.ReadyToRun; |
||||
|
||||
namespace ICSharpCode.ILSpy.ReadyToRun |
||||
{ |
||||
[Export(typeof(Language))] |
||||
internal class ReadyToRunLanguage : Language |
||||
{ |
||||
private static readonly ConditionalWeakTable<PEFile, R2RReaderCacheEntry> r2rReaders = new ConditionalWeakTable<PEFile, R2RReaderCacheEntry>(); |
||||
public override string Name => "ReadyToRun"; |
||||
|
||||
public override string FileExtension { |
||||
get { return ".asm"; } |
||||
} |
||||
|
||||
public override ProjectId DecompileAssembly(LoadedAssembly assembly, ITextOutput output, DecompilationOptions options) |
||||
{ |
||||
PEFile module = assembly.GetPEFileOrNull(); |
||||
R2RReaderCacheEntry r2rReaderCacheEntry = GetReader(assembly, module); |
||||
if (r2rReaderCacheEntry.r2rReader == null) { |
||||
WriteCommentLine(output, r2rReaderCacheEntry.failureReason); |
||||
} else { |
||||
R2RReader reader = r2rReaderCacheEntry.r2rReader; |
||||
WriteCommentLine(output, "TODO - display ready to run information"); |
||||
// TODO: display other header information
|
||||
foreach (var method in reader.R2RMethods) { |
||||
WriteCommentLine(output, method.SignatureString); |
||||
} |
||||
} |
||||
|
||||
return base.DecompileAssembly(assembly, output, options); |
||||
} |
||||
|
||||
public override void DecompileMethod(IMethod method, ITextOutput output, DecompilationOptions options) |
||||
{ |
||||
PEFile module = method.ParentModule.PEFile; |
||||
R2RReaderCacheEntry r2rReaderCacheEntry = GetReader(module.GetLoadedAssembly(), module); |
||||
if (r2rReaderCacheEntry.r2rReader == null) { |
||||
WriteCommentLine(output, r2rReaderCacheEntry.failureReason); |
||||
} else { |
||||
R2RReader reader = r2rReaderCacheEntry.r2rReader; |
||||
int bitness = -1; |
||||
if (reader.Machine == Machine.Amd64) { |
||||
bitness = 64; |
||||
} else { |
||||
Debug.Assert(reader.Machine == Machine.I386); |
||||
bitness = 32; |
||||
} |
||||
foreach (var m in reader.R2RMethods) { |
||||
if (m.MethodHandle == method.MetadataToken) { |
||||
// TODO: Indexing
|
||||
foreach (RuntimeFunction runtimeFunction in m.RuntimeFunctions) { |
||||
WriteCommentLine(output, m.SignatureString); |
||||
byte[] code = new byte[runtimeFunction.Size]; |
||||
for (int i = 0; i < runtimeFunction.Size; i++) { |
||||
code[i] = reader.Image[reader.GetOffset(runtimeFunction.StartAddress) + i]; |
||||
} |
||||
Disassemble(output, code, bitness, (ulong)runtimeFunction.StartAddress); |
||||
output.WriteLine(); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
public override void WriteCommentLine(ITextOutput output, string comment) |
||||
{ |
||||
output.WriteLine("; " + comment); |
||||
} |
||||
|
||||
private void Disassemble(ITextOutput output, byte[] codeBytes, int bitness, ulong address) |
||||
{ |
||||
// TODO: Decorate the disassembly with Unwind, GC and debug info
|
||||
var codeReader = new ByteArrayCodeReader(codeBytes); |
||||
var decoder = Decoder.Create(bitness, codeReader); |
||||
decoder.IP = address; |
||||
ulong endRip = decoder.IP + (uint)codeBytes.Length; |
||||
|
||||
var instructions = new InstructionList(); |
||||
while (decoder.IP < endRip) { |
||||
decoder.Decode(out instructions.AllocUninitializedElement()); |
||||
} |
||||
|
||||
string disassemblyFormat = ReadyToRunOptions.GetDisassemblyFormat(null); |
||||
Formatter formatter = null; |
||||
if (disassemblyFormat.Equals(ReadyToRunOptions.intel)) { |
||||
formatter = new NasmFormatter(); |
||||
} else { |
||||
Debug.Assert(disassemblyFormat.Equals(ReadyToRunOptions.gas)); |
||||
formatter = new GasFormatter(); |
||||
} |
||||
formatter.Options.DigitSeparator = "`"; |
||||
formatter.Options.FirstOperandCharIndex = 10; |
||||
var tempOutput = new StringBuilderFormatterOutput(); |
||||
foreach (var instr in instructions) { |
||||
formatter.Format(instr, tempOutput); |
||||
output.Write(instr.IP.ToString("X16")); |
||||
output.Write(" "); |
||||
int instrLen = instr.ByteLength; |
||||
int byteBaseIndex = (int)(instr.IP - address); |
||||
for (int i = 0; i < instrLen; i++) |
||||
output.Write(codeBytes[byteBaseIndex + i].ToString("X2")); |
||||
int missingBytes = 10 - instrLen; |
||||
for (int i = 0; i < missingBytes; i++) |
||||
output.Write(" "); |
||||
output.Write(" "); |
||||
output.WriteLine(tempOutput.ToStringAndReset()); |
||||
} |
||||
} |
||||
|
||||
private R2RReaderCacheEntry GetReader(LoadedAssembly assembly, PEFile module) |
||||
{ |
||||
R2RReaderCacheEntry result; |
||||
lock (r2rReaders) { |
||||
if (!r2rReaders.TryGetValue(module, out result)) { |
||||
result = new R2RReaderCacheEntry(); |
||||
try { |
||||
// TODO: avoid eager parsing
|
||||
result.r2rReader = new R2RReader(new R2RAssemblyResolver(assembly), module.Metadata, module.Reader, module.FileName); |
||||
if (result.r2rReader.Machine != Machine.Amd64 && result.r2rReader.Machine != Machine.I386) { |
||||
result.failureReason = $"Architecture {result.r2rReader.Machine} is not currently supported."; |
||||
result.r2rReader = null; |
||||
} |
||||
} catch (BadImageFormatException e) { |
||||
result.failureReason = e.Message; |
||||
} |
||||
r2rReaders.Add(module, result); |
||||
} |
||||
} |
||||
return result; |
||||
} |
||||
|
||||
private class R2RAssemblyResolver : ILCompiler.Reflection.ReadyToRun.IAssemblyResolver |
||||
{ |
||||
private LoadedAssembly loadedAssembly; |
||||
public R2RAssemblyResolver(LoadedAssembly loadedAssembly) |
||||
{ |
||||
this.loadedAssembly = loadedAssembly; |
||||
} |
||||
public bool Naked => false; |
||||
|
||||
public bool SignatureBinary => false; |
||||
|
||||
public bool InlineSignatureBinary => false; |
||||
|
||||
public MetadataReader FindAssembly(MetadataReader metadataReader, AssemblyReferenceHandle assemblyReferenceHandle, string parentFile) |
||||
{ |
||||
LoadedAssembly loadedAssembly = this.loadedAssembly.LookupReferencedAssembly(new Decompiler.Metadata.AssemblyReference(metadataReader, assemblyReferenceHandle)); |
||||
return loadedAssembly?.GetPEFileOrNull()?.Metadata; |
||||
} |
||||
} |
||||
|
||||
private class R2RReaderCacheEntry |
||||
{ |
||||
public R2RReader r2rReader; |
||||
public string failureReason; |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,10 @@
@@ -0,0 +1,10 @@
|
||||
<UserControl x:Class="ICSharpCode.ILSpy.ReadyToRun.ReadyToRunOptionPage" |
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"> |
||||
<StackPanel> |
||||
<StackPanel Orientation="Horizontal"> |
||||
<TextBlock>Disassembly Format</TextBlock> |
||||
<ComboBox ItemsSource="{Binding DisassemblyFormats}" SelectedItem="{Binding DisassemblyFormat}"/> |
||||
</StackPanel> |
||||
</StackPanel> |
||||
</UserControl> |
@ -0,0 +1,82 @@
@@ -0,0 +1,82 @@
|
||||
// Copyright (c) 2018 Siegfried Pammer
|
||||
//
|
||||
// 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.ComponentModel; |
||||
using System.Windows.Controls; |
||||
using System.Xml.Linq; |
||||
using ICSharpCode.ILSpy.Options; |
||||
|
||||
namespace ICSharpCode.ILSpy.ReadyToRun |
||||
{ |
||||
[ExportOptionPage(Title = "ReadyToRun", Order = 0)] |
||||
partial class ReadyToRunOptionPage : UserControl, IOptionPage |
||||
{ |
||||
public ReadyToRunOptionPage() |
||||
{ |
||||
InitializeComponent(); |
||||
} |
||||
|
||||
public void Load(ILSpySettings settings) |
||||
{ |
||||
Options s = new Options(); |
||||
s.DisassemblyFormat = ReadyToRunOptions.GetDisassemblyFormat(settings); |
||||
this.DataContext = s; |
||||
} |
||||
|
||||
public void LoadDefaults() |
||||
{ |
||||
this.DataContext = new Options(); |
||||
} |
||||
|
||||
public void Save(XElement root) |
||||
{ |
||||
Options s = (Options)this.DataContext; |
||||
ReadyToRunOptions.SetDisassemblyFormat(root, s.DisassemblyFormat); |
||||
} |
||||
} |
||||
|
||||
internal class Options : INotifyPropertyChanged |
||||
{ |
||||
public string[] DisassemblyFormats { |
||||
get { |
||||
return ReadyToRunOptions.disassemblyFormats; |
||||
} |
||||
} |
||||
|
||||
private string disassemblyFormat; |
||||
|
||||
public string DisassemblyFormat { |
||||
get { return disassemblyFormat; } |
||||
set { |
||||
if (disassemblyFormat != value) { |
||||
disassemblyFormat = value; |
||||
OnPropertyChanged(nameof(DisassemblyFormat)); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged; |
||||
|
||||
protected virtual void OnPropertyChanged(string propertyName) |
||||
{ |
||||
if (PropertyChanged != null) { |
||||
PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,58 @@
@@ -0,0 +1,58 @@
|
||||
// Copyright (c) 2018 Siegfried Pammer
|
||||
//
|
||||
// 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.Xml.Linq; |
||||
|
||||
namespace ICSharpCode.ILSpy.ReadyToRun |
||||
{ |
||||
internal class ReadyToRunOptions |
||||
{ |
||||
private static readonly XNamespace ns = "http://www.ilspy.net/ready-to-run"; |
||||
|
||||
internal static string intel = "Intel"; |
||||
internal static string gas = "AT & T"; |
||||
internal static string[] disassemblyFormats = new string[] { intel, gas }; |
||||
|
||||
public static string GetDisassemblyFormat(ILSpySettings settings) |
||||
{ |
||||
if (settings == null) { |
||||
settings = ILSpySettings.Load(); |
||||
} |
||||
XElement e = settings[ns + "ReadyToRunOptions"]; |
||||
XAttribute a = e.Attribute("DisassemblyFormat"); |
||||
if (a == null) { |
||||
return ReadyToRunOptions.intel; |
||||
} else { |
||||
return (string)a; |
||||
} |
||||
} |
||||
|
||||
public static void SetDisassemblyFormat(XElement root, string disassemblyFormat) |
||||
{ |
||||
XElement section = new XElement(ns + "ReadyToRunOptions"); |
||||
section.SetAttributeValue("DisassemblyFormat", disassemblyFormat); |
||||
|
||||
XElement existingElement = root.Element(ns + "ReadyToRunOptions"); |
||||
if (existingElement != null) { |
||||
existingElement.ReplaceWith(section); |
||||
} else { |
||||
root.Add(section); |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue