diff --git a/src/Pdb2Xml/PdbToXml.cs b/src/Pdb2Xml/PdbToXml.cs index e21ae0a9..1ab2d0fa 100644 --- a/src/Pdb2Xml/PdbToXml.cs +++ b/src/Pdb2Xml/PdbToXml.cs @@ -3,8 +3,12 @@ // See the License.txt file in the project root for more information. using System; +using System.Collections.Immutable; using System.IO; using System.Linq; +using System.Reflection; +using System.Reflection.Metadata; +using System.Reflection.PortableExecutable; using System.Text; namespace Microsoft.DiaSymReader.Tools @@ -162,7 +166,12 @@ public static void Convert(Args args) if (!File.Exists(pdbFile)) { - throw new FileNotFoundException($"PDB File not found: {pdbFile}"); + if (!ProcessEmbeddedPdb(peFile, args.OutputPath, args.Options)) + { + throw new FileNotFoundException($"PDB File not found: {pdbFile}"); + } + + return; } if (args.Delta) @@ -175,6 +184,52 @@ public static void Convert(Args args) } } + public static bool ProcessEmbeddedPdb(string? assemblyFilePath, string outputPath, PdbToXmlOptions options) + { + if (assemblyFilePath == null) + { + return false; + } + + MemoryStream? pdbStream = null; + + using (var stream = File.OpenRead(assemblyFilePath)) + { + var reader = new PEReader(stream); + var metadataReader = reader.GetMetadataReader(); + var debugDirectory = reader.ReadDebugDirectory(); + foreach (var entry in debugDirectory) + { + if (entry.Type == DebugDirectoryEntryType.EmbeddedPortablePdb && entry.DataSize > 0) + { + var embeddedProvider = reader.ReadEmbeddedPortablePdbDebugDirectoryData(entry); + var memoryBlock = embeddedProvider.GetType().GetMethod("GetMetadataBlock", BindingFlags.Instance | BindingFlags.NonPublic).Invoke(embeddedProvider, null); + var memoryBlockType = memoryBlock.GetType(); + var size = (int)memoryBlockType.GetProperty("Size").GetValue(memoryBlock); + var bytes = (ImmutableArray)memoryBlockType.GetMethod("GetContentUnchecked").Invoke(memoryBlock, new object[] { 0, size }); + pdbStream = new MemoryStream(bytes.ToArray()); + break; + } + } + } + + if (pdbStream == null) + { + return false; + } + + using (var stream = File.OpenRead(assemblyFilePath)) + { + var xmlText = PdbToXmlConverter.ToXml(pdbStream, stream, options); + + outputPath = Path.GetFullPath(outputPath); + Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); + File.WriteAllText(outputPath, xmlText); + } + + return true; + } + public static void GenXmlFromPdb(string exePath, string pdbPath, string outPath, PdbToXmlOptions options) { using var peStream = new FileStream(exePath, FileMode.Open, FileAccess.Read);