Skip to content

Commit

Permalink
Generate PDBs locally if needed (#22)
Browse files Browse the repository at this point in the history
* generate PDBs locally if needed

 * integrate ILSpy for decompiling DLLs if needed
 * if PDB doesn't exist already, use ILSpy to generate it

* bring PDB writer from ILSpy decompiler here

* continue if generation fails

* fix few null dereference issues
  • Loading branch information
tuxology authored Mar 20, 2024
1 parent 3c7ac4e commit eb369ed
Show file tree
Hide file tree
Showing 4 changed files with 718 additions and 2 deletions.
2 changes: 2 additions & 0 deletions DotNetAstGen/DotNetAstGen.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

<ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1" />
<PackageReference Include="ICSharpCode.Decompiler" Version="8.2.0.7535" />
<PackageReference Include="ICSharpCode.ILSpyX" Version="8.2.0.7535" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.NewtonsoftJson" Version="3.0.0" />
<PackageReference Include="Microsoft.CodeAnalysis" Version="4.8.0" />
<PackageReference Include="Mono.Cecil" Version="0.11.5" />
Expand Down
63 changes: 63 additions & 0 deletions DotNetAstGen/PDBGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
using ICSharpCode.Decompiler.DebugInfo;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Solution;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpyX.PdbProvider;

using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using Microsoft.Extensions.Logging;

namespace DotNetAstGen
{
public class PDBGenerator
{
public static ILoggerFactory? LoggerFactory;
private static ILogger<PDBGenerator>? _logger;

private static DecompilerSettings GetSettings(PEFile module)
{
return new DecompilerSettings(ICSharpCode.Decompiler.CSharp.LanguageVersion.Latest)
{
ThrowOnAssemblyResolveErrors = false,
RemoveDeadCode = false,
RemoveDeadStores = false,
UseSdkStyleProjectFormat = WholeProjectDecompiler.CanUseSdkStyleProjectFormat(module),
UseNestedDirectoriesForNamespaces = false,
};
}
private static CSharpDecompiler GetDecompiler(string assemblyFileName)
{
var module = new PEFile(assemblyFileName);
var resolver = new UniversalAssemblyResolver(assemblyFileName, false, module.Metadata.DetectTargetFrameworkId());
return new CSharpDecompiler(assemblyFileName, resolver, GetSettings(module));
}
public void GeneratePDBforDLLFile(string dllFileName, string pdbFileName)
{
using ILoggerFactory factory = Microsoft.Extensions.Logging.LoggerFactory.Create(builder => builder.AddConsole());
_logger = factory.CreateLogger<PDBGenerator>();

var module = new PEFile(dllFileName,
new FileStream(dllFileName, FileMode.Open, FileAccess.Read),
PEStreamOptions.PrefetchEntireImage,
metadataOptions: MetadataReaderOptions.None);

if (!PDBWriter.HasCodeViewDebugDirectoryEntry(module))
{
_logger?.LogWarning($"Cannot create PDB file for {dllFileName}, because it does not contain a PE Debug Directory Entry of type 'CodeView'. Skipping...");
}
else
{
using (FileStream stream = new FileStream(pdbFileName, FileMode.OpenOrCreate, FileAccess.Write))
{
var decompiler = GetDecompiler(dllFileName);
PDBWriter.WritePdb(module, decompiler, GetSettings(module), stream);
}
}
}
}
}
Loading

0 comments on commit eb369ed

Please sign in to comment.