Skip to content
Permalink
Browse files

Merge pull request #1740 from icsharpcode/issue1677

Fix issue 1677
  • Loading branch information...
siegfriedpammer committed Oct 22, 2019
2 parents 99fc4d8 + 99cc610 commit f07bfeca51f01ac418000ebb786093523982f194
@@ -22,7 +22,7 @@ namespace ICSharpCode.Decompiler.Console
-o is valid with every option and required when using -p.
")]
[HelpOption("-h|--help")]
[ProjectOptionRequiresOutputDirectoryValidationAttribute]
[ProjectOptionRequiresOutputDirectoryValidation]
class ILSpyCmdProgram
{
public static int Main(string[] args) => CommandLineApplication.Execute<ILSpyCmdProgram>(args);
@@ -54,18 +54,27 @@ class ILSpyCmdProgram
[Option("-v|--version", "Show version of ICSharpCode.Decompiler used.", CommandOptionType.NoValue)]
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]
[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];

[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)
{
TextWriter output = System.Console.Out;
bool outputDirectorySpecified = !String.IsNullOrEmpty(OutputDirectory);
bool outputDirectorySpecified = !string.IsNullOrEmpty(OutputDirectory);

try {
if (CreateCompilableProjectFlag) {
DecompileAsProject(InputAssemblyName, OutputDirectory, ReferencePaths);
return DecompileAsProject(InputAssemblyName, OutputDirectory);
} else if (EntityTypes.Any()) {
var values = EntityTypes.SelectMany(v => v.Split(',', ';')).ToArray();
HashSet<TypeKind> kinds = TypesParser.ParseSelection(values);
@@ -74,14 +83,14 @@ private int OnExecute(CommandLineApplication app)
output = File.CreateText(Path.Combine(OutputDirectory, outputName) + ".list.txt");
}

ListContent(InputAssemblyName, output, kinds, ReferencePaths);
return ListContent(InputAssemblyName, output, kinds);
} else if (ShowILCodeFlag) {
if (outputDirectorySpecified) {
string outputName = Path.GetFileNameWithoutExtension(InputAssemblyName);
output = File.CreateText(Path.Combine(OutputDirectory, outputName) + ".il");
}

ShowIL(InputAssemblyName, output, ReferencePaths);
return ShowIL(InputAssemblyName, output);
} else if (CreateDebugInfoFlag) {
string pdbFileName = null;
if (outputDirectorySpecified) {
@@ -91,7 +100,7 @@ private int OnExecute(CommandLineApplication app)
pdbFileName = Path.ChangeExtension(InputAssemblyName, ".pdb");
}

return GeneratePdbForAssembly(InputAssemblyName, pdbFileName, ReferencePaths, app);
return GeneratePdbForAssembly(InputAssemblyName, pdbFileName, app);
} else if (ShowVersion) {
string vInfo = "ilspycmd: " + typeof(ILSpyCmdProgram).Assembly.GetName().Version.ToString() +
Environment.NewLine
@@ -102,10 +111,10 @@ private int OnExecute(CommandLineApplication app)
if (outputDirectorySpecified) {
string outputName = Path.GetFileNameWithoutExtension(InputAssemblyName);
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) {
app.Error.WriteLine(ex.ToString());
@@ -117,66 +126,73 @@ private int OnExecute(CommandLineApplication app)
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 resolver = new UniversalAssemblyResolver(assemblyFileName, false, module.Reader.DetectTargetFrameworkId());
foreach (var path in referencePaths) {
foreach (var path in ReferencePaths) {
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) {
if (!kinds.Contains(type.Kind))
continue;
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);
ITextOutput textOutput = new PlainTextOutput();
ReflectionDisassembler disassembler = new ReflectionDisassembler(textOutput, CancellationToken.None);

disassembler.DisassembleNamespace(decompiler.TypeSystem.MainModule.RootNamespace.Name,
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());
var module = new PEFile(assemblyFileName);
output.WriteLine($"// IL code: {module.Name}");
var disassembler = new ReflectionDisassembler(new PlainTextOutput(output), CancellationToken.None);
disassembler.WriteModuleContents(module);
return 0;
}

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 resolver = new UniversalAssemblyResolver(assemblyFileName, false, module.Reader.DetectTargetFrameworkId());
foreach (var path in referencePaths) {
foreach (var path in ReferencePaths) {
resolver.AddSearchDirectory(path);
}
decompiler.AssemblyResolver = resolver;
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) {
output.Write(decompiler.DecompileWholeModuleAsString());
} else {
var name = new FullTypeName(typeName);
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,
new FileStream(assemblyFileName, FileMode.Open, FileAccess.Read),
@@ -189,8 +205,8 @@ static int GeneratePdbForAssembly(string assemblyFileName, string pdbFileName, s
}

using (FileStream stream = new FileStream(pdbFileName, FileMode.OpenOrCreate, FileAccess.Write)) {
var decompiler = GetDecompiler(assemblyFileName, referencePaths);
PortablePdbWriter.WritePdb(module, decompiler, new DecompilerSettings() { ThrowOnAssemblyResolveErrors = false }, stream);
var decompiler = GetDecompiler(assemblyFileName);
PortablePdbWriter.WritePdb(module, decompiler, GetSettings(), stream);
}

return 0;
@@ -14,17 +14,21 @@ dotnet tool for decompiling .NET assemblies and generating portable PDBs
Usage: ilspycmd [arguments] [options]
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:
-h|--help Show help information
-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.
-t|--type <type-name> The fully qualified name of the type to decompile.
-il|--ilcode Show IL code.
-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)
-v|--version Show version of ICSharpCode.Decompiler used.
-h|--help Show help information
-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.
-t|--type <type-name> The fully qualified name of the type to decompile.
-il|--ilcode Show IL code.
-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)
-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:
-o is valid with every option and required when using -p.
@@ -15,13 +15,24 @@ public class GetDecompilerCmdlet : PSCmdlet
[ValidateNotNullOrEmpty]
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()
{
string path = GetUnresolvedProviderPathFromPSPath(LiteralPath);

try {
var decompiler = new CSharpDecompiler(path, new DecompilerSettings() {
ThrowOnAssemblyResolveErrors = false
var decompiler = new CSharpDecompiler(path, new DecompilerSettings(LanguageVersion) {
ThrowOnAssemblyResolveErrors = false,
RemoveDeadCode = RemoveDeadCode,
RemoveDeadStores = RemoveDeadStores
});
WriteObject(decompiler);

0 comments on commit f07bfec

Please sign in to comment.
You can’t perform that action at this time.