Browse Source

Merge pull request #1740 from icsharpcode/issue1677

Fix issue 1677
pull/1763/head
Siegfried Pammer 6 years ago committed by GitHub
parent
commit
f07bfeca51
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 80
      ICSharpCode.Decompiler.Console/IlspyCmdProgram.cs
  2. 22
      ICSharpCode.Decompiler.Console/README.md
  3. 15
      ICSharpCode.Decompiler.PowerShell/GetDecompilerCmdlet.cs

80
ICSharpCode.Decompiler.Console/IlspyCmdProgram.cs

@ -22,7 +22,7 @@ Remarks:
-o is valid with every option and required when using -p. -o is valid with every option and required when using -p.
")] ")]
[HelpOption("-h|--help")] [HelpOption("-h|--help")]
[ProjectOptionRequiresOutputDirectoryValidationAttribute] [ProjectOptionRequiresOutputDirectoryValidation]
class ILSpyCmdProgram class ILSpyCmdProgram
{ {
public static int Main(string[] args) => CommandLineApplication.Execute<ILSpyCmdProgram>(args); public static int Main(string[] args) => CommandLineApplication.Execute<ILSpyCmdProgram>(args);
@ -54,18 +54,27 @@ Remarks:
[Option("-v|--version", "Show version of ICSharpCode.Decompiler used.", CommandOptionType.NoValue)] [Option("-v|--version", "Show version of ICSharpCode.Decompiler used.", CommandOptionType.NoValue)]
public bool ShowVersion { get; } public bool ShowVersion { get; }
[Option("-lv|--languageversion", "C# Language version: CSharp1, CSharp2, CSharp3, CSharp4, CSharp5, CSharp6, CSharp7_0, CSharp7_1, CSharp7_2, CSharp7_3, CSharp8_0 or Latest", CommandOptionType.SingleValue)]
public LanguageVersion LanguageVersion { get; } = LanguageVersion.Latest;
[DirectoryExists] [DirectoryExists]
[Option("-r|--referencepath <path>", "Path to a directory containing dependencies of the assembly that is being decompiled.", CommandOptionType.MultipleValue)] [Option("-r|--referencepath <path>", "Path to a directory containing dependencies of the assembly that is being decompiled.", CommandOptionType.MultipleValue)]
public string[] ReferencePaths { get; } = new string[0]; public string[] ReferencePaths { get; } = new string[0];
[Option("--no-dead-code", "Remove dead code.", CommandOptionType.NoValue)]
public bool RemoveDeadCode { get; }
[Option("--no-dead-stores", "Remove dead stores.", CommandOptionType.NoValue)]
public bool RemoveDeadStores { get; }
private int OnExecute(CommandLineApplication app) private int OnExecute(CommandLineApplication app)
{ {
TextWriter output = System.Console.Out; TextWriter output = System.Console.Out;
bool outputDirectorySpecified = !String.IsNullOrEmpty(OutputDirectory); bool outputDirectorySpecified = !string.IsNullOrEmpty(OutputDirectory);
try { try {
if (CreateCompilableProjectFlag) { if (CreateCompilableProjectFlag) {
DecompileAsProject(InputAssemblyName, OutputDirectory, ReferencePaths); return DecompileAsProject(InputAssemblyName, OutputDirectory);
} else if (EntityTypes.Any()) { } else if (EntityTypes.Any()) {
var values = EntityTypes.SelectMany(v => v.Split(',', ';')).ToArray(); var values = EntityTypes.SelectMany(v => v.Split(',', ';')).ToArray();
HashSet<TypeKind> kinds = TypesParser.ParseSelection(values); HashSet<TypeKind> kinds = TypesParser.ParseSelection(values);
@ -74,14 +83,14 @@ Remarks:
output = File.CreateText(Path.Combine(OutputDirectory, outputName) + ".list.txt"); output = File.CreateText(Path.Combine(OutputDirectory, outputName) + ".list.txt");
} }
ListContent(InputAssemblyName, output, kinds, ReferencePaths); return ListContent(InputAssemblyName, output, kinds);
} else if (ShowILCodeFlag) { } else if (ShowILCodeFlag) {
if (outputDirectorySpecified) { if (outputDirectorySpecified) {
string outputName = Path.GetFileNameWithoutExtension(InputAssemblyName); string outputName = Path.GetFileNameWithoutExtension(InputAssemblyName);
output = File.CreateText(Path.Combine(OutputDirectory, outputName) + ".il"); output = File.CreateText(Path.Combine(OutputDirectory, outputName) + ".il");
} }
ShowIL(InputAssemblyName, output, ReferencePaths); return ShowIL(InputAssemblyName, output);
} else if (CreateDebugInfoFlag) { } else if (CreateDebugInfoFlag) {
string pdbFileName = null; string pdbFileName = null;
if (outputDirectorySpecified) { if (outputDirectorySpecified) {
@ -91,7 +100,7 @@ Remarks:
pdbFileName = Path.ChangeExtension(InputAssemblyName, ".pdb"); pdbFileName = Path.ChangeExtension(InputAssemblyName, ".pdb");
} }
return GeneratePdbForAssembly(InputAssemblyName, pdbFileName, ReferencePaths, app); return GeneratePdbForAssembly(InputAssemblyName, pdbFileName, app);
} else if (ShowVersion) { } else if (ShowVersion) {
string vInfo = "ilspycmd: " + typeof(ILSpyCmdProgram).Assembly.GetName().Version.ToString() + string vInfo = "ilspycmd: " + typeof(ILSpyCmdProgram).Assembly.GetName().Version.ToString() +
Environment.NewLine Environment.NewLine
@ -102,10 +111,10 @@ Remarks:
if (outputDirectorySpecified) { if (outputDirectorySpecified) {
string outputName = Path.GetFileNameWithoutExtension(InputAssemblyName); string outputName = Path.GetFileNameWithoutExtension(InputAssemblyName);
output = File.CreateText(Path.Combine(OutputDirectory, output = File.CreateText(Path.Combine(OutputDirectory,
(String.IsNullOrEmpty(TypeName) ? outputName : TypeName) + ".decompiled.cs")); (string.IsNullOrEmpty(TypeName) ? outputName : TypeName) + ".decompiled.cs"));
} }
Decompile(InputAssemblyName, output, ReferencePaths, TypeName); return Decompile(InputAssemblyName, output, TypeName);
} }
} catch (Exception ex) { } catch (Exception ex) {
app.Error.WriteLine(ex.ToString()); app.Error.WriteLine(ex.ToString());
@ -117,56 +126,62 @@ Remarks:
return 0; return 0;
} }
static CSharpDecompiler GetDecompiler(string assemblyFileName, string[] referencePaths) DecompilerSettings GetSettings()
{
return new DecompilerSettings(LanguageVersion) {
ThrowOnAssemblyResolveErrors = false,
RemoveDeadCode = RemoveDeadCode,
RemoveDeadStores = RemoveDeadStores
};
}
CSharpDecompiler GetDecompiler(string assemblyFileName)
{ {
var module = new PEFile(assemblyFileName); var module = new PEFile(assemblyFileName);
var resolver = new UniversalAssemblyResolver(assemblyFileName, false, module.Reader.DetectTargetFrameworkId()); var resolver = new UniversalAssemblyResolver(assemblyFileName, false, module.Reader.DetectTargetFrameworkId());
foreach (var path in referencePaths) { foreach (var path in ReferencePaths) {
resolver.AddSearchDirectory(path); resolver.AddSearchDirectory(path);
} }
return new CSharpDecompiler(assemblyFileName, resolver, new DecompilerSettings()); return new CSharpDecompiler(assemblyFileName, resolver, GetSettings());
} }
static void ListContent(string assemblyFileName, TextWriter output, ISet<TypeKind> kinds, string[] referencePaths) int ListContent(string assemblyFileName, TextWriter output, ISet<TypeKind> kinds)
{ {
CSharpDecompiler decompiler = GetDecompiler(assemblyFileName, referencePaths); CSharpDecompiler decompiler = GetDecompiler(assemblyFileName);
foreach (var type in decompiler.TypeSystem.MainModule.TypeDefinitions) { foreach (var type in decompiler.TypeSystem.MainModule.TypeDefinitions) {
if (!kinds.Contains(type.Kind)) if (!kinds.Contains(type.Kind))
continue; continue;
output.WriteLine($"{type.Kind} {type.FullName}"); output.WriteLine($"{type.Kind} {type.FullName}");
} }
return 0;
} }
static void ShowIL(string assemblyFileName, TextWriter output, string[] referencePaths) int ShowIL(string assemblyFileName, TextWriter output)
{ {
CSharpDecompiler decompiler = GetDecompiler(assemblyFileName, referencePaths); var module = new PEFile(assemblyFileName);
ITextOutput textOutput = new PlainTextOutput(); output.WriteLine($"// IL code: {module.Name}");
ReflectionDisassembler disassembler = new ReflectionDisassembler(textOutput, CancellationToken.None); var disassembler = new ReflectionDisassembler(new PlainTextOutput(output), CancellationToken.None);
disassembler.WriteModuleContents(module);
disassembler.DisassembleNamespace(decompiler.TypeSystem.MainModule.RootNamespace.Name, return 0;
decompiler.TypeSystem.MainModule.PEFile,
decompiler.TypeSystem.MainModule.TypeDefinitions.Select(x => (TypeDefinitionHandle)x.MetadataToken));
output.WriteLine($"// IL code: {decompiler.TypeSystem.MainModule.AssemblyName}");
output.WriteLine(textOutput.ToString());
} }
static void DecompileAsProject(string assemblyFileName, string outputDirectory, string[] referencePaths) int DecompileAsProject(string assemblyFileName, string outputDirectory)
{ {
var decompiler = new WholeProjectDecompiler(); var decompiler = new WholeProjectDecompiler() { Settings = GetSettings() };
var module = new PEFile(assemblyFileName); var module = new PEFile(assemblyFileName);
var resolver = new UniversalAssemblyResolver(assemblyFileName, false, module.Reader.DetectTargetFrameworkId()); var resolver = new UniversalAssemblyResolver(assemblyFileName, false, module.Reader.DetectTargetFrameworkId());
foreach (var path in referencePaths) { foreach (var path in ReferencePaths) {
resolver.AddSearchDirectory(path); resolver.AddSearchDirectory(path);
} }
decompiler.AssemblyResolver = resolver; decompiler.AssemblyResolver = resolver;
decompiler.DecompileProject(module, outputDirectory); decompiler.DecompileProject(module, outputDirectory);
return 0;
} }
static void Decompile(string assemblyFileName, TextWriter output, string[] referencePaths, string typeName = null) int Decompile(string assemblyFileName, TextWriter output, string typeName = null)
{ {
CSharpDecompiler decompiler = GetDecompiler(assemblyFileName, referencePaths); CSharpDecompiler decompiler = GetDecompiler(assemblyFileName);
if (typeName == null) { if (typeName == null) {
output.Write(decompiler.DecompileWholeModuleAsString()); output.Write(decompiler.DecompileWholeModuleAsString());
@ -174,9 +189,10 @@ Remarks:
var name = new FullTypeName(typeName); var name = new FullTypeName(typeName);
output.Write(decompiler.DecompileTypeAsString(name)); output.Write(decompiler.DecompileTypeAsString(name));
} }
return 0;
} }
static int GeneratePdbForAssembly(string assemblyFileName, string pdbFileName, string[] referencePaths, CommandLineApplication app) int GeneratePdbForAssembly(string assemblyFileName, string pdbFileName, CommandLineApplication app)
{ {
var module = new PEFile(assemblyFileName, var module = new PEFile(assemblyFileName,
new FileStream(assemblyFileName, FileMode.Open, FileAccess.Read), new FileStream(assemblyFileName, FileMode.Open, FileAccess.Read),
@ -189,8 +205,8 @@ Remarks:
} }
using (FileStream stream = new FileStream(pdbFileName, FileMode.OpenOrCreate, FileAccess.Write)) { using (FileStream stream = new FileStream(pdbFileName, FileMode.OpenOrCreate, FileAccess.Write)) {
var decompiler = GetDecompiler(assemblyFileName, referencePaths); var decompiler = GetDecompiler(assemblyFileName);
PortablePdbWriter.WritePdb(module, decompiler, new DecompilerSettings() { ThrowOnAssemblyResolveErrors = false }, stream); PortablePdbWriter.WritePdb(module, decompiler, GetSettings(), stream);
} }
return 0; return 0;

22
ICSharpCode.Decompiler.Console/README.md

@ -14,17 +14,21 @@ dotnet tool for decompiling .NET assemblies and generating portable PDBs
Usage: ilspycmd [arguments] [options] Usage: ilspycmd [arguments] [options]
Arguments: Arguments:
Assembly file name The assembly that is being decompiled. This argument is mandatory. Assembly file name The assembly that is being decompiled. This argument is mandatory.
Options: Options:
-h|--help Show help information -h|--help Show help information
-o|--outputdir <directory> The output directory, if omitted decompiler output is written to standard out. -o|--outputdir <directory> The output directory, if omitted decompiler output is written to standard out.
-p|--project Decompile assembly as compilable project. This requires the output directory option. -p|--project Decompile assembly as compilable project. This requires the output directory option.
-t|--type <type-name> The fully qualified name of the type to decompile. -t|--type <type-name> The fully qualified name of the type to decompile.
-il|--ilcode Show IL code. -il|--ilcode Show IL code.
-d|--debuginfo Generate PDB. -d|--debuginfo Generate PDB.
-l|--list <entity-type(s)> Lists all entities of the specified type(s). Valid types: c(lass), i(interface), s(truct), d(elegate), e(num) -l|--list <entity-type(s)> Lists all entities of the specified type(s). Valid types: c(lass), i(interface), s(truct), d(elegate), e(num)
-v|--version Show version of ICSharpCode.Decompiler used. -v|--version Show version of ICSharpCode.Decompiler used.
-lv|--languageversion <version> C# Language version: CSharp1, CSharp2, CSharp3, CSharp4, CSharp5, CSharp6, CSharp7_0, CSharp7_1, CSharp7_2, CSharp7_3, CSharp8_0 or Latest
-r|--referencepath <path> Path to a directory containing dependencies of the assembly that is being decompiled.
--no-dead-code Remove dead code.
--no-dead-stores Remove dead stores.
Remarks: Remarks:
-o is valid with every option and required when using -p. -o is valid with every option and required when using -p.

15
ICSharpCode.Decompiler.PowerShell/GetDecompilerCmdlet.cs

@ -15,13 +15,24 @@ namespace ICSharpCode.Decompiler.PowerShell
[ValidateNotNullOrEmpty] [ValidateNotNullOrEmpty]
public string LiteralPath { get; set; } public string LiteralPath { get; set; }
[Parameter(HelpMessage = "C# Language version to be used by the decompiler")]
public LanguageVersion LanguageVersion { get; set; } = LanguageVersion.Latest;
[Parameter(HelpMessage = "Remove dead stores")]
public bool RemoveDeadStores { get; set; }
[Parameter(HelpMessage = "Remove dead code")]
public bool RemoveDeadCode { get; set; }
protected override void ProcessRecord() protected override void ProcessRecord()
{ {
string path = GetUnresolvedProviderPathFromPSPath(LiteralPath); string path = GetUnresolvedProviderPathFromPSPath(LiteralPath);
try { try {
var decompiler = new CSharpDecompiler(path, new DecompilerSettings() { var decompiler = new CSharpDecompiler(path, new DecompilerSettings(LanguageVersion) {
ThrowOnAssemblyResolveErrors = false ThrowOnAssemblyResolveErrors = false,
RemoveDeadCode = RemoveDeadCode,
RemoveDeadStores = RemoveDeadStores
}); });
WriteObject(decompiler); WriteObject(decompiler);

Loading…
Cancel
Save