diff --git a/ICSharpCode.Decompiler.Console/Program.cs b/ICSharpCode.Decompiler.Console/Program.cs index 9286c4e47..4948ca2ac 100644 --- a/ICSharpCode.Decompiler.Console/Program.cs +++ b/ICSharpCode.Decompiler.Console/Program.cs @@ -9,11 +9,20 @@ using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Disassembler; using System.Threading; using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; +using ICSharpCode.Decompiler.DebugInfo; +// ReSharper disable InconsistentNaming namespace ICSharpCode.Decompiler.Console { class Program { + // https://www.freebsd.org/cgi/man.cgi?query=sysexits&apropos=0&sektion=0&manpath=FreeBSD+4.3-RELEASE&format=html + private const int EX_USAGE = 64; + private const int EX_DATAERR = 65; + private const int EX_NOINPUT = 66; + private const int EX_SOFTWARE = 70; + static int Main(string[] args) { // https://github.com/natemcmaster/CommandLineUtils/ @@ -28,6 +37,7 @@ namespace ICSharpCode.Decompiler.Console var typeOption = app.Option("-t|--type ", "The fully qualified name of the type to decompile.", CommandOptionType.SingleValue); var listOption = app.Option("-l|--list ", "Lists all entities of the specified type(s). Valid types: c(lass), i(interface), s(truct), d(elegate), e(num)", CommandOptionType.MultipleValue); var ilViewerOption = app.Option("-il|--ilcode", "Show IL code.", CommandOptionType.NoValue); + var pdbGeneration = app.Option("-d|--debuginfo", "Generate PDB.", CommandOptionType.NoValue); app.ExtendedHelpText = Environment.NewLine + "-o is valid with every option and required when using -p."; app.ThrowOnUnexpectedArgument = false; // Ignore invalid arguments / options @@ -42,15 +52,15 @@ namespace ICSharpCode.Decompiler.Console } if (!File.Exists(inputAssemblyFileName.Value)) { app.Error.WriteLine($"ERROR: Input file not found."); - return -1; + return EX_NOINPUT; } if (!outputOption.HasValue() && projectOption.HasValue()) { app.Error.WriteLine($"ERROR: Output directory not speciified."); - return -1; + return EX_USAGE; } if (outputOption.HasValue() && !Directory.Exists(outputOption.Value())) { app.Error.WriteLine($"ERROR: Output directory '{outputOption.Value()}' does not exist."); - return -1; + return EX_NOINPUT; } TextWriter output = System.Console.Out; try { @@ -72,6 +82,16 @@ namespace ICSharpCode.Decompiler.Console output = File.CreateText(Path.Combine(directory, outputName) + ".il"); } ShowIL(inputAssemblyFileName.Value, output); + } else if (pdbGeneration.HasValue()) { + string pdbFileName = null; + if (outputOption.HasValue()) { + string directory = outputOption.Value(); + string outputName = Path.GetFileNameWithoutExtension(inputAssemblyFileName.Value); + pdbFileName = Path.Combine(directory, outputName) + ".pdb"; + } else { + pdbFileName = Path.ChangeExtension(inputAssemblyFileName.Value, ".pdb"); + } + return GeneratePdbForAssembly(inputAssemblyFileName.Value, pdbFileName, app); } else { if (outputOption.HasValue()) { string directory = outputOption.Value(); @@ -139,5 +159,31 @@ namespace ICSharpCode.Decompiler.Console output.Write(decompiler.DecompileTypeAsString(name)); } } + + static int GeneratePdbForAssembly(string assemblyFileName, string pdbFileName, CommandLineApplication app) + { + var module = new PEFile(assemblyFileName, + new FileStream(assemblyFileName, FileMode.Open, FileAccess.Read), + PEStreamOptions.PrefetchEntireImage, + metadataOptions: MetadataReaderOptions.None); + + if (!PortablePdbWriter.HasCodeViewDebugDirectoryEntry(module)) { + app.Error.WriteLine($"Cannot create PDB file for {assemblyFileName}, because it does not contain a PE Debug Directory Entry of type 'CodeView'."); + return EX_DATAERR; + } + + using (FileStream stream = new FileStream(pdbFileName, FileMode.OpenOrCreate, FileAccess.Write)) { + try { + var decompiler = GetDecompiler(assemblyFileName); + PortablePdbWriter.WritePdb(module, decompiler, new DecompilerSettings() { ThrowOnAssemblyResolveErrors = false }, stream); + } catch (Exception ex) { + app.Error.WriteLine($"Cannot create PDB file for {assemblyFileName}"); + app.Error.WriteLine(ex.ToString()); + return EX_SOFTWARE; + } + } + + return 0; + } } }