From e68aa72eadd394aa4610547de6c4509926d61b0b Mon Sep 17 00:00:00 2001 From: ElektroKill Date: Fri, 11 Nov 2022 19:26:10 +0100 Subject: [PATCH 1/4] Add support for new Roslyn CustomDebugInfo --- src/DotNet/Pdb/CustomDebugInfoGuids.cs | 2 + src/DotNet/Pdb/PdbCustomDebugInfo.cs | 148 +++++++++++++++++- .../PortablePdbCustomDebugInfoReader.cs | 33 ++++ .../PortablePdbCustomDebugInfoWriter.cs | 30 ++++ 4 files changed, 210 insertions(+), 3 deletions(-) diff --git a/src/DotNet/Pdb/CustomDebugInfoGuids.cs b/src/DotNet/Pdb/CustomDebugInfoGuids.cs index 95acf760b..1002f6877 100644 --- a/src/DotNet/Pdb/CustomDebugInfoGuids.cs +++ b/src/DotNet/Pdb/CustomDebugInfoGuids.cs @@ -20,6 +20,8 @@ public static class CustomDebugInfoGuids { public static readonly Guid TupleElementNames = new Guid("ED9FDF71-8879-4747-8ED3-FE5EDE3CE710"); public static readonly Guid CompilationMetadataReferences = new Guid("7E4D4708-096E-4C5C-AEDA-CB10BA6A740D"); public static readonly Guid CompilationOptions = new Guid("B5FEEC05-8CD0-4A83-96DA-466284BB4BD8"); + public static readonly Guid TypeDefinitionDocuments = new Guid("932E74BC-DBA9-4478-8D46-0F32A7BAB3D3"); + public static readonly Guid EncStateMachineStateMap = new Guid("8B78CD68-2EDE-420B-980B-E15884B8AAA3"); #pragma warning restore 1591 // Missing XML comment for publicly visible type or member } } diff --git a/src/DotNet/Pdb/PdbCustomDebugInfo.cs b/src/DotNet/Pdb/PdbCustomDebugInfo.cs index 55909f8c6..62fdbbb53 100644 --- a/src/DotNet/Pdb/PdbCustomDebugInfo.cs +++ b/src/DotNet/Pdb/PdbCustomDebugInfo.cs @@ -111,6 +111,16 @@ public enum PdbCustomDebugInfoKind { /// /// CompilationOptions, + + /// + /// + /// + TypeDefinitionDocuments, + + /// + /// + /// + EditAndContinueStateMachineStateMap, } /// @@ -665,7 +675,7 @@ public sealed class PortablePdbTupleElementNamesCustomDebugInfo : PdbCustomDebug /// /// Async method stepping info - /// + /// /// It's internal and translated to a /// sealed class PdbAsyncMethodSteppingInformationCustomDebugInfo : PdbCustomDebugInfo { @@ -777,9 +787,9 @@ public sealed class PdbEmbeddedSourceCustomDebugInfo : PdbCustomDebugInfo { /// /// Gets the source code blob. - /// + /// /// It's not decompressed and converted to a string because the encoding isn't specified. - /// + /// /// https://github.com/dotnet/corefx/blob/master/src/System.Reflection.Metadata/specs/PortablePdb-Metadata.md#embedded-source-c-and-vb-compilers /// public byte[] SourceCodeBlob { get; set; } @@ -1101,4 +1111,136 @@ public sealed class PdbCompilationOptionsCustomDebugInfo : PdbCustomDebugInfo { /// public PdbCompilationOptionsCustomDebugInfo() => Options = new List>(); } + + /// + /// Links a TypeDef with no method IL with a PDB document. + /// + public sealed class PdbTypeDefinitionDocumentsDebugInfo : PdbCustomDebugInfo { + /// + /// Returns + /// + public override PdbCustomDebugInfoKind Kind => PdbCustomDebugInfoKind.TypeDefinitionDocuments; + + /// + /// Gets the custom debug info guid, see + /// + public override Guid Guid => CustomDebugInfoGuids.TypeDefinitionDocuments; + + /// + /// Document tokens. Only resolvable in debug metadata. + /// A token like this can be resolved by subtracting 1 from the RID and using it as an index into the + /// PdbState.Documents enumerable. + /// + public List DocumentTokens { get; } + + /// + /// Constructor + /// + public PdbTypeDefinitionDocumentsDebugInfo() => DocumentTokens = new List(); + } + + /// + /// Contains the EnC state machine state mapping + /// + public sealed class PdbEditAndContinueStateMachineStateMapDebugInfo : PdbCustomDebugInfo { + /// + /// Returns + /// + public override PdbCustomDebugInfoKind Kind => PdbCustomDebugInfoKind.EditAndContinueStateMachineStateMap; + + /// + /// Gets the custom debug info guid, see + /// + public override Guid Guid => CustomDebugInfoGuids.EncStateMachineStateMap; + + /// + /// State machine states + /// + public List StateMachineStates { get; } + + /// + /// Constructor + /// + public PdbEditAndContinueStateMachineStateMapDebugInfo() => StateMachineStates = new List(); + } + + /// + /// State machine state information used by debuggers + /// + public struct StateMachineStateInfo { + /// + /// Syntax offset + /// + public readonly int SyntaxOffset; + + /// + /// State machine state + /// + public readonly StateMachineState State; + + /// + /// Constructor + /// + /// Syntax offset + /// State machine state + public StateMachineStateInfo(int syntaxOffset, StateMachineState state) { + SyntaxOffset = syntaxOffset; + State = state; + } + } + + /// + /// State machine state + /// from Roslyn: StateMachineState.cs + /// + public enum StateMachineState { + /// + /// First state of an async iterator state machine that is used to resume the machine after yield return. + /// Initial state is not used to resume state machine that yielded. State numbers decrease as the iterator makes progress. + /// + FirstResumableAsyncIteratorState = InitialAsyncIteratorState - 1, + + /// + /// Initial iterator state of an async iterator. + /// Distinct from so that DisposeAsync can throw in latter case. + /// + InitialAsyncIteratorState = -3, + + /// + /// First state of an iterator state machine. State numbers decrease for subsequent finalize states. + /// + FirstIteratorFinalizeState = -3, + + /// + /// The last state of a state machine. + /// + FinishedState = -2, + + /// + /// State machine not started or is running + /// + NotStartedOrRunningState = -1, + + /// + /// First unused state + /// + FirstUnusedState = 0, + + /// + /// First state in async state machine that is used to resume the machine after await. + /// State numbers increase as the async computation makes progress. + /// + FirstResumableAsyncState = 0, + + /// + /// Initial iterator state of an iterator. + /// + InitialIteratorState = 0, + + /// + /// First state in iterator state machine that is used to resume the machine after yield return. + /// Initial state is not used to resume state machine that yielded. State numbers increase as the iterator makes progress. + /// + FirstResumableIteratorState = InitialIteratorState + 1, + } } diff --git a/src/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoReader.cs b/src/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoReader.cs index 68b61ee80..e9e1fa477 100644 --- a/src/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoReader.cs +++ b/src/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoReader.cs @@ -65,6 +65,10 @@ PdbCustomDebugInfo Read(Guid kind) { return ReadCompilationMetadataReferences(); if (kind == CustomDebugInfoGuids.CompilationOptions) return ReadCompilationOptions(); + if (kind == CustomDebugInfoGuids.TypeDefinitionDocuments) + return ReadTypeDefinitionDocuments(); + if (kind == CustomDebugInfoGuids.EncStateMachineStateMap) + return ReadEncStateMachineStateMap(); Debug.Fail("Unknown custom debug info guid: " + kind.ToString()); return new PdbUnknownCustomDebugInfo(kind, reader.ReadRemainingBytes()); } @@ -228,6 +232,35 @@ PdbCustomDebugInfo ReadCompilationOptions() { return cdi; } + PdbCustomDebugInfo ReadTypeDefinitionDocuments() { + var cdi = new PdbTypeDefinitionDocumentsDebugInfo(); + + while (reader.BytesLeft > 0) + cdi.DocumentTokens.Add(new MDToken(Table.Document, reader.ReadCompressedUInt32())); + + return cdi; + } + + PdbCustomDebugInfo ReadEncStateMachineStateMap() { + var cdi = new PdbEditAndContinueStateMachineStateMapDebugInfo(); + + var count = reader.ReadCompressedUInt32(); + if (count > 0) { + long syntaxOffsetBaseline = -reader.ReadCompressedUInt32(); + + while (count > 0) { + int stateNumber = reader.ReadCompressedInt32(); + int syntaxOffset = (int)(syntaxOffsetBaseline + reader.ReadCompressedUInt32()); + + cdi.StateMachineStates.Add(new StateMachineStateInfo(syntaxOffset, (StateMachineState)stateNumber)); + + count--; + } + } + + return cdi; + } + Instruction GetInstruction(uint offset) { var instructions = bodyOpt.Instructions; int lo = 0, hi = instructions.Count - 1; diff --git a/src/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoWriter.cs b/src/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoWriter.cs index 0729c602e..780f3ebfb 100644 --- a/src/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoWriter.cs +++ b/src/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoWriter.cs @@ -1,6 +1,8 @@ // dnlib: See LICENSE.txt for more info +using System; using System.IO; +using System.Linq; using System.Text; using dnlib.DotNet.Emit; using dnlib.DotNet.Writer; @@ -92,6 +94,14 @@ byte[] Write(PdbCustomDebugInfo cdi) { case PdbCustomDebugInfoKind.CompilationOptions: WriteCompilationOptions((PdbCompilationOptionsCustomDebugInfo)cdi); break; + + case PdbCustomDebugInfoKind.TypeDefinitionDocuments: + WriteTypeDefinitionDocuments((PdbTypeDefinitionDocumentsDebugInfo)cdi); + break; + + case PdbCustomDebugInfoKind.EditAndContinueStateMachineStateMap: + WriteEditAndContinueStateMachineStateMap((PdbEditAndContinueStateMachineStateMapDebugInfo)cdi); + break; } return outStream.ToArray(); } @@ -317,5 +327,25 @@ void WriteCompilationOptions(PdbCompilationOptionsCustomDebugInfo cdi) { WriteUTF8Z(kv.Value); } } + + void WriteTypeDefinitionDocuments(PdbTypeDefinitionDocumentsDebugInfo cdi) { + foreach (var docToken in cdi.DocumentTokens) + writer.WriteCompressedUInt32(docToken.Rid); + } + + void WriteEditAndContinueStateMachineStateMap(PdbEditAndContinueStateMachineStateMapDebugInfo cdi) { + writer.WriteCompressedUInt32((uint)cdi.StateMachineStates.Count); + + if (cdi.StateMachineStates.Count <= 0) + return; + + int syntaxOffsetBaseline = Math.Min(cdi.StateMachineStates.Min(state => state.SyntaxOffset), 0); + writer.WriteCompressedUInt32((uint)-syntaxOffsetBaseline); + + foreach (var state in cdi.StateMachineStates) { + writer.WriteCompressedInt32((int)state.State); + writer.WriteCompressedUInt32((uint)(state.SyntaxOffset - syntaxOffsetBaseline)); + } + } } } From e666538fd1ec733f0af8c57a3a96f5582ea704c0 Mon Sep 17 00:00:00 2001 From: ElektroKill Date: Sat, 12 Nov 2022 11:47:56 +0100 Subject: [PATCH 2/4] Add missing switch cases --- src/DotNet/Writer/Metadata.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/DotNet/Writer/Metadata.cs b/src/DotNet/Writer/Metadata.cs index df93b83e1..37bcc490a 100644 --- a/src/DotNet/Writer/Metadata.cs +++ b/src/DotNet/Writer/Metadata.cs @@ -3384,6 +3384,8 @@ void AddCustomDebugInformation(SerializerMethodContext serializerMethodContext, case PdbCustomDebugInfoKind.SourceLink: case PdbCustomDebugInfoKind.CompilationMetadataReferences: case PdbCustomDebugInfoKind.CompilationOptions: + case PdbCustomDebugInfoKind.TypeDefinitionDocuments: + case PdbCustomDebugInfoKind.EditAndContinueStateMachineStateMap: AddCustomDebugInformationCore(serializerMethodContext, encodedToken, cdi, cdi.Guid); break; From 45d6e881bb6e2edbab1386d5252dad890e175440 Mon Sep 17 00:00:00 2001 From: ElektroKill Date: Tue, 15 Nov 2022 19:09:01 +0100 Subject: [PATCH 3/4] Addressed feedback --- src/DotNet/Pdb/Dss/SymbolDocumentImpl.cs | 2 + src/DotNet/Pdb/Managed/DbiDocument.cs | 2 + src/DotNet/Pdb/PdbCustomDebugInfo.cs | 42 +++++++++++++++---- src/DotNet/Pdb/PdbState.cs | 5 ++- .../PortablePdbCustomDebugInfoReader.cs | 7 ++-- .../PortablePdbCustomDebugInfoWriter.cs | 4 +- src/DotNet/Pdb/Portable/PortablePdbReader.cs | 8 ++-- src/DotNet/Pdb/Portable/SymbolDocumentImpl.cs | 5 ++- src/DotNet/Pdb/Symbols/SymbolDocument.cs | 5 +++ 9 files changed, 60 insertions(+), 20 deletions(-) diff --git a/src/DotNet/Pdb/Dss/SymbolDocumentImpl.cs b/src/DotNet/Pdb/Dss/SymbolDocumentImpl.cs index 062f6820d..650797db3 100644 --- a/src/DotNet/Pdb/Dss/SymbolDocumentImpl.cs +++ b/src/DotNet/Pdb/Dss/SymbolDocumentImpl.cs @@ -89,5 +89,7 @@ public override PdbCustomDebugInfo[] CustomDebugInfos { } } PdbCustomDebugInfo[] customDebugInfos; + + public override MDToken? MDToken => null; } } diff --git a/src/DotNet/Pdb/Managed/DbiDocument.cs b/src/DotNet/Pdb/Managed/DbiDocument.cs index b13f70d6f..fde9e87a3 100644 --- a/src/DotNet/Pdb/Managed/DbiDocument.cs +++ b/src/DotNet/Pdb/Managed/DbiDocument.cs @@ -38,6 +38,8 @@ public override PdbCustomDebugInfo[] CustomDebugInfos { } PdbCustomDebugInfo[] customDebugInfos; + public override MDToken? MDToken => null; + public DbiDocument(string url) { this.url = url; documentType = SymDocumentType.Text; diff --git a/src/DotNet/Pdb/PdbCustomDebugInfo.cs b/src/DotNet/Pdb/PdbCustomDebugInfo.cs index 62fdbbb53..d92c25185 100644 --- a/src/DotNet/Pdb/PdbCustomDebugInfo.cs +++ b/src/DotNet/Pdb/PdbCustomDebugInfo.cs @@ -2,6 +2,7 @@ using System; using System.Collections.Generic; +using System.Threading; using dnlib.DotNet.Emit; namespace dnlib.DotNet.Pdb { @@ -1115,7 +1116,7 @@ public sealed class PdbCompilationOptionsCustomDebugInfo : PdbCustomDebugInfo { /// /// Links a TypeDef with no method IL with a PDB document. /// - public sealed class PdbTypeDefinitionDocumentsDebugInfo : PdbCustomDebugInfo { + public class PdbTypeDefinitionDocumentsDebugInfo : PdbCustomDebugInfo { /// /// Returns /// @@ -1127,16 +1128,39 @@ public sealed class PdbTypeDefinitionDocumentsDebugInfo : PdbCustomDebugInfo { public override Guid Guid => CustomDebugInfoGuids.TypeDefinitionDocuments; /// - /// Document tokens. Only resolvable in debug metadata. - /// A token like this can be resolved by subtracting 1 from the RID and using it as an index into the - /// PdbState.Documents enumerable. + /// List of documents associated with the type /// - public List DocumentTokens { get; } + public IList Documents { + get { + if (documents is null) + InitializeDocuments(); + return documents; + } + } + /// + protected IList documents; + /// Initializes + protected virtual void InitializeDocuments() => + Interlocked.CompareExchange(ref documents, new List(), null); + } - /// - /// Constructor - /// - public PdbTypeDefinitionDocumentsDebugInfo() => DocumentTokens = new List(); + class PdbTypeDefinitionDocumentsDebugInfoMD : PdbTypeDefinitionDocumentsDebugInfo { + readonly ModuleDef readerModule; + readonly IList documentTokens; + + protected override void InitializeDocuments() { + var list = new List(documentTokens.Count); + for (var i = 0; i < documentTokens.Count; i++) { + if (readerModule.PdbState.tokenToDocument.TryGetValue(documentTokens[i], out var document)) + list.Add(document); + } + Interlocked.CompareExchange(ref documents, list, null); + } + + public PdbTypeDefinitionDocumentsDebugInfoMD(ModuleDef readerModule, IList documentTokens) { + this.readerModule = readerModule; + this.documentTokens = documentTokens; + } } /// diff --git a/src/DotNet/Pdb/PdbState.cs b/src/DotNet/Pdb/PdbState.cs index 455c24d11..45ab7004c 100644 --- a/src/DotNet/Pdb/PdbState.cs +++ b/src/DotNet/Pdb/PdbState.cs @@ -15,6 +15,7 @@ namespace dnlib.DotNet.Pdb { public sealed class PdbState { readonly SymbolReader reader; readonly Dictionary docDict = new Dictionary(); + internal readonly Dictionary tokenToDocument = new Dictionary(); MethodDef userEntryPoint; readonly Compiler compiler; readonly PdbFileKind originalPdbFileKind; @@ -64,7 +65,7 @@ public bool HasDocuments { #if THREAD_SAFE } finally { theLock.ExitWriteLock(); } #endif - + } } @@ -133,6 +134,8 @@ PdbDocument Add_NoLock(SymbolDocument symDoc) { // Expensive part, can read source code etc doc.Initialize(symDoc); docDict.Add(doc, doc); + if (symDoc.MDToken.HasValue) + tokenToDocument.Add(symDoc.MDToken.Value, doc); return doc; } diff --git a/src/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoReader.cs b/src/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoReader.cs index e9e1fa477..5a1e1705d 100644 --- a/src/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoReader.cs +++ b/src/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoReader.cs @@ -233,12 +233,11 @@ PdbCustomDebugInfo ReadCompilationOptions() { } PdbCustomDebugInfo ReadTypeDefinitionDocuments() { - var cdi = new PdbTypeDefinitionDocumentsDebugInfo(); - + var docList = new List(); while (reader.BytesLeft > 0) - cdi.DocumentTokens.Add(new MDToken(Table.Document, reader.ReadCompressedUInt32())); + docList.Add(new MDToken(Table.Document, reader.ReadCompressedUInt32())); - return cdi; + return new PdbTypeDefinitionDocumentsDebugInfoMD(module, docList); } PdbCustomDebugInfo ReadEncStateMachineStateMap() { diff --git a/src/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoWriter.cs b/src/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoWriter.cs index 780f3ebfb..789d3ee4a 100644 --- a/src/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoWriter.cs +++ b/src/DotNet/Pdb/Portable/PortablePdbCustomDebugInfoWriter.cs @@ -329,8 +329,8 @@ void WriteCompilationOptions(PdbCompilationOptionsCustomDebugInfo cdi) { } void WriteTypeDefinitionDocuments(PdbTypeDefinitionDocumentsDebugInfo cdi) { - foreach (var docToken in cdi.DocumentTokens) - writer.WriteCompressedUInt32(docToken.Rid); + foreach (var document in cdi.Documents) + writer.WriteCompressedUInt32(systemMetadata.GetRid(document)); } void WriteEditAndContinueStateMachineStateMap(PdbEditAndContinueStateMachineStateMapDebugInfo cdi) { diff --git a/src/DotNet/Pdb/Portable/PortablePdbReader.cs b/src/DotNet/Pdb/Portable/PortablePdbReader.cs index fc8fdec37..bae2ae621 100644 --- a/src/DotNet/Pdb/Portable/PortablePdbReader.cs +++ b/src/DotNet/Pdb/Portable/PortablePdbReader.cs @@ -61,7 +61,8 @@ SymbolDocument[] ReadDocuments() { var custInfos = ListCache.AllocList(); var gpContext = new GenericParamContext(); for (int i = 0; i < docs.Length; i++) { - bool b = pdbMetadata.TablesStream.TryReadDocumentRow((uint)i + 1, out var row); + uint rid = (uint)i + 1; + bool b = pdbMetadata.TablesStream.TryReadDocumentRow(rid, out var row); Debug.Assert(b); var url = nameReader.ReadDocumentName(row.Name); var language = pdbMetadata.GuidStream.Read(row.Language) ?? Guid.Empty; @@ -70,12 +71,13 @@ SymbolDocument[] ReadDocuments() { var checkSumAlgorithmId = pdbMetadata.GuidStream.Read(row.HashAlgorithm) ?? Guid.Empty; var checkSum = pdbMetadata.BlobStream.ReadNoNull(row.Hash); - var token = new MDToken(Table.Document, i + 1).ToInt32(); + var mdToken = new MDToken(Table.Document, rid); + var token = mdToken.ToInt32(); custInfos.Clear(); GetCustomDebugInfos(token, gpContext, custInfos); var custInfosArray = custInfos.Count == 0 ? Array2.Empty() : custInfos.ToArray(); - docs[i] = new SymbolDocumentImpl(url, language, languageVendor, documentType, checkSumAlgorithmId, checkSum, custInfosArray); + docs[i] = new SymbolDocumentImpl(url, language, languageVendor, documentType, checkSumAlgorithmId, checkSum, custInfosArray, mdToken); } ListCache.Free(ref custInfos); return docs; diff --git a/src/DotNet/Pdb/Portable/SymbolDocumentImpl.cs b/src/DotNet/Pdb/Portable/SymbolDocumentImpl.cs index 7168d3c85..dce64fb4a 100644 --- a/src/DotNet/Pdb/Portable/SymbolDocumentImpl.cs +++ b/src/DotNet/Pdb/Portable/SymbolDocumentImpl.cs @@ -15,6 +15,7 @@ sealed class SymbolDocumentImpl : SymbolDocument { /*readonly*/ Guid checkSumAlgorithmId; readonly byte[] checkSum; readonly PdbCustomDebugInfo[] customDebugInfos; + MDToken mdToken; string GetDebuggerString() { var sb = new StringBuilder(); @@ -45,8 +46,9 @@ string GetDebuggerString() { public override Guid CheckSumAlgorithmId => checkSumAlgorithmId; public override byte[] CheckSum => checkSum; public override PdbCustomDebugInfo[] CustomDebugInfos => customDebugInfos; + public override MDToken? MDToken => mdToken; - public SymbolDocumentImpl(string url, Guid language, Guid languageVendor, Guid documentType, Guid checkSumAlgorithmId, byte[] checkSum, PdbCustomDebugInfo[] customDebugInfos) { + public SymbolDocumentImpl(string url, Guid language, Guid languageVendor, Guid documentType, Guid checkSumAlgorithmId, byte[] checkSum, PdbCustomDebugInfo[] customDebugInfos, MDToken mdToken) { this.url = url; this.language = language; this.languageVendor = languageVendor; @@ -54,6 +56,7 @@ public SymbolDocumentImpl(string url, Guid language, Guid languageVendor, Guid d this.checkSumAlgorithmId = checkSumAlgorithmId; this.checkSum = checkSum; this.customDebugInfos = customDebugInfos; + this.mdToken = mdToken; } } } diff --git a/src/DotNet/Pdb/Symbols/SymbolDocument.cs b/src/DotNet/Pdb/Symbols/SymbolDocument.cs index ec12ded6b..58509969e 100644 --- a/src/DotNet/Pdb/Symbols/SymbolDocument.cs +++ b/src/DotNet/Pdb/Symbols/SymbolDocument.cs @@ -41,5 +41,10 @@ public abstract class SymbolDocument { /// Gets the custom debug infos /// public abstract PdbCustomDebugInfo[] CustomDebugInfos { get; } + + /// + /// Gets the Metadata token of the document if available. + /// + public abstract MDToken? MDToken { get; } } } From 5ac12c36daa56af996873cbed141381cfd809216 Mon Sep 17 00:00:00 2001 From: ElektroKill Date: Thu, 17 Nov 2022 18:54:16 +0100 Subject: [PATCH 4/4] Addressed feedback --- src/DotNet/Pdb/PdbCustomDebugInfo.cs | 10 ++++++---- src/DotNet/Pdb/PdbDocument.cs | 6 ++++++ src/DotNet/Pdb/PdbState.cs | 5 +++++ 3 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/DotNet/Pdb/PdbCustomDebugInfo.cs b/src/DotNet/Pdb/PdbCustomDebugInfo.cs index d92c25185..39f5853cf 100644 --- a/src/DotNet/Pdb/PdbCustomDebugInfo.cs +++ b/src/DotNet/Pdb/PdbCustomDebugInfo.cs @@ -1144,15 +1144,17 @@ protected virtual void InitializeDocuments() => Interlocked.CompareExchange(ref documents, new List(), null); } - class PdbTypeDefinitionDocumentsDebugInfoMD : PdbTypeDefinitionDocumentsDebugInfo { + sealed class PdbTypeDefinitionDocumentsDebugInfoMD : PdbTypeDefinitionDocumentsDebugInfo { readonly ModuleDef readerModule; readonly IList documentTokens; protected override void InitializeDocuments() { var list = new List(documentTokens.Count); - for (var i = 0; i < documentTokens.Count; i++) { - if (readerModule.PdbState.tokenToDocument.TryGetValue(documentTokens[i], out var document)) - list.Add(document); + if (readerModule.PdbState is not null) { + for (var i = 0; i < documentTokens.Count; i++) { + if (readerModule.PdbState.tokenToDocument.TryGetValue(documentTokens[i], out var document)) + list.Add(document); + } } Interlocked.CompareExchange(ref documents, list, null); } diff --git a/src/DotNet/Pdb/PdbDocument.cs b/src/DotNet/Pdb/PdbDocument.cs index b38fe311c..6f25bbe8c 100644 --- a/src/DotNet/Pdb/PdbDocument.cs +++ b/src/DotNet/Pdb/PdbDocument.cs @@ -53,6 +53,11 @@ public sealed class PdbDocument : IHasCustomDebugInformation { public IList CustomDebugInfos => customDebugInfos; IList customDebugInfos; + /// + /// Gets the Metadata token of the document if available. + /// + public MDToken? MDToken { get; internal set; } + /// /// Default constructor /// @@ -86,6 +91,7 @@ internal void Initialize(SymbolDocument symDoc) { customDebugInfos = new List(); foreach (var cdi in symDoc.CustomDebugInfos) customDebugInfos.Add(cdi); + MDToken = symDoc.MDToken; } /// diff --git a/src/DotNet/Pdb/PdbState.cs b/src/DotNet/Pdb/PdbState.cs index 45ab7004c..39146563f 100644 --- a/src/DotNet/Pdb/PdbState.cs +++ b/src/DotNet/Pdb/PdbState.cs @@ -124,6 +124,8 @@ PdbDocument Add_NoLock(PdbDocument doc) { if (docDict.TryGetValue(doc, out var orig)) return orig; docDict.Add(doc, doc); + if (doc.MDToken.HasValue) + tokenToDocument.Add(doc.MDToken.Value, doc); return doc; } @@ -148,6 +150,8 @@ public bool Remove(PdbDocument doc) { #if THREAD_SAFE theLock.EnterWriteLock(); try { #endif + if (doc.MDToken.HasValue) + tokenToDocument.Remove(doc.MDToken.Value); return docDict.Remove(doc); #if THREAD_SAFE } finally { theLock.ExitWriteLock(); } @@ -189,6 +193,7 @@ public List RemoveAllDocuments(bool returnDocs) { theLock.EnterWriteLock(); try { #endif var docs = returnDocs ? new List(docDict.Values) : null; + tokenToDocument.Clear(); docDict.Clear(); return docs; #if THREAD_SAFE