public static EditAndContinueMethodDebugInformation GetEncMethodDebugInfo(byte[] customDebugInfoBlob) { var localSlots = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(customDebugInfoBlob, CustomDebugInfoKind.EditAndContinueLocalSlotMap); var lambdaMap = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(customDebugInfoBlob, CustomDebugInfoKind.EditAndContinueLambdaMap); return(EditAndContinueMethodDebugInformation.Create(localSlots, lambdaMap)); }
public void BadPdb_Cycle() { const int methodToken1 = 0x600057a; // Forwards to itself var getMethodCustomDebugInfo = new Func <int, int, byte[]>((token, _) => { switch (token) { case methodToken1: return(new MethodDebugInfoBytes.Builder().AddForward(methodToken1).Build().Bytes.ToArray()); default: throw null; } }); var getMethodImportStrings = new Func <int, int, ImmutableArray <string> >((token, _) => { return(ImmutableArray <string> .Empty); }); ImmutableArray <string> externAliasStrings; var importStrings = CustomDebugInfoReader.GetCSharpGroupedImportStrings(methodToken1, 0, getMethodCustomDebugInfo, getMethodImportStrings, out externAliasStrings); Assert.True(importStrings.IsDefault); Assert.True(externAliasStrings.IsDefault); }
private static bool TryCreateImportRecordFromCSharpImportString(EESymbolProvider <TTypeSymbol, TLocalSymbol> symbolProvider, string importString, out ImportRecord record) { ImportTargetKind targetKind; string externAlias; string alias; string targetString; if (CustomDebugInfoReader.TryParseCSharpImportString(importString, out alias, out externAlias, out targetString, out targetKind)) { ITypeSymbol type = null; if (targetKind == ImportTargetKind.Type) { type = symbolProvider.GetTypeSymbolForSerializedType(targetString); targetString = null; } record = new ImportRecord( targetKind: targetKind, alias: alias, targetType: type, targetString: targetString, targetAssembly: null, targetAssemblyAlias: externAlias); return(true); } record = default(ImportRecord); return(false); }
private static void ReadCSharpNativeCustomDebugInfo( ISymUnmanagedReader reader, int methodToken, int methodVersion, IEnumerable <ISymUnmanagedScope> scopes, out ImmutableArray <HoistedLocalScopeRecord> hoistedLocalScopeRecords, out ImmutableDictionary <int, ImmutableArray <bool> > dynamicLocalMap, out ImmutableDictionary <string, ImmutableArray <bool> > dynamicLocalConstantMap) { hoistedLocalScopeRecords = ImmutableArray <HoistedLocalScopeRecord> .Empty; dynamicLocalMap = ImmutableDictionary <int, ImmutableArray <bool> > .Empty; dynamicLocalConstantMap = ImmutableDictionary <string, ImmutableArray <bool> > .Empty; byte[] customDebugInfoBytes = reader.GetCustomDebugInfoBytes(methodToken, methodVersion); if (customDebugInfoBytes == null) { return; } var customDebugInfoRecord = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(customDebugInfoBytes, CustomDebugInfoKind.StateMachineHoistedLocalScopes); if (!customDebugInfoRecord.IsDefault) { hoistedLocalScopeRecords = CustomDebugInfoReader.DecodeStateMachineHoistedLocalScopesRecord(customDebugInfoRecord) .SelectAsArray(s => new HoistedLocalScopeRecord(s.StartOffset, s.EndOffset - s.StartOffset + 1)); } CustomDebugInfoReader.GetCSharpDynamicLocalInfo( customDebugInfoBytes, methodToken, methodVersion, scopes, out dynamicLocalMap, out dynamicLocalConstantMap); }
public void InvalidAlignment_KindDoesntSupportAlignment() { // CDIs that don't support alignment: var bytes = new byte[] { 0x04, // version 0x01, // count 0x00, 0x00, 0x04, // version 0x01, // kind 0x11, // invalid data 0x14, // invalid data // body size 0x0c, 0x00, 0x00, 0x00, // payload 0x01, 0x00, 0x00, 0x06 }; var records = CustomDebugInfoReader.GetCustomDebugInfoRecords(bytes).ToArray(); Assert.Equal(1, records.Length); Assert.Equal(CustomDebugInfoKind.ForwardInfo, records[0].Kind); Assert.Equal(4, records[0].Version); AssertEx.Equal(new byte[] { 0x01, 0x00, 0x00, 0x06 }, records[0].Data); }
public static ImmutableArray <byte> GetEditAndContinueLambdaMapRecord( byte[] customDebugInfoBlob ) { return(CustomDebugInfoReader.TryGetCustomDebugInfoRecord( customDebugInfoBlob, CustomDebugInfoKind.EditAndContinueLambdaMap )); }
private static void ReadVisualBasicImportsDebugInfo( ISymUnmanagedReader reader, int methodToken, int methodVersion, out ImmutableArray <ImmutableArray <ImportRecord> > importRecordGroups, out string defaultNamespaceName) { importRecordGroups = ImmutableArray <ImmutableArray <ImportRecord> > .Empty; var importStrings = CustomDebugInfoReader.GetVisualBasicImportStrings( methodToken, KeyValuePairUtil.Create(reader, methodVersion), (token, arg) => GetImportStrings(arg.Key, token, arg.Value)); if (importStrings.IsDefault) { defaultNamespaceName = ""; return; } string?lazyDefaultNamespaceName = null; var projectLevelImportRecords = ArrayBuilder <ImportRecord> .GetInstance(); var fileLevelImportRecords = ArrayBuilder <ImportRecord> .GetInstance(); foreach (var importString in importStrings) { RoslynDebug.AssertNotNull(importString); if (importString.Length > 0 && importString[0] == '*') { string?alias = null; string?target = null; if (!CustomDebugInfoReader.TryParseVisualBasicImportString(importString, out alias, out target, out var kind, out var scope)) { Debug.WriteLine($"Unable to parse import string '{importString}'"); continue; } else if (kind == ImportTargetKind.Defunct) { continue; } Debug.Assert(alias == null); // The default namespace is never aliased. Debug.Assert(target != null); Debug.Assert(kind == ImportTargetKind.DefaultNamespace); // We only expect to see one of these, but it looks like ProcedureContext::LoadImportsAndDefaultNamespaceNormal // implicitly uses the last one if there are multiple. Debug.Assert(lazyDefaultNamespaceName == null); lazyDefaultNamespaceName = target; }
/// <summary> /// Given a byte array of custom debug info, parse the array and write out XML describing /// its structure and contents. /// </summary> private void WriteCustomDebugInfo(byte[] bytes) { var records = CustomDebugInfoReader.GetCustomDebugInfoRecords(bytes).ToArray(); writer.WriteStartElement("customDebugInfo"); foreach (var record in records) { if (record.Version != CDIC.CdiVersion) { WriteUnknownCustomDebugInfo(record); } else { switch (record.Kind) { case CustomDebugInfoKind.UsingInfo: WriteUsingCustomDebugInfo(record); break; case CustomDebugInfoKind.ForwardInfo: WriteForwardCustomDebugInfo(record); break; case CustomDebugInfoKind.ForwardToModuleInfo: WriteForwardToModuleCustomDebugInfo(record); break; case CustomDebugInfoKind.StateMachineHoistedLocalScopes: WriteStatemachineHoistedLocalScopesCustomDebugInfo(record); break; case CustomDebugInfoKind.ForwardIterator: WriteForwardIteratorCustomDebugInfo(record); break; case CustomDebugInfoKind.DynamicLocals: WriteDynamicLocalsCustomDebugInfo(record); break; case CustomDebugInfoKind.EditAndContinueLocalSlotMap: WriteEditAndContinueLocalSlotMap(record); break; default: WriteUnknownCustomDebugInfo(record); break; } } } writer.WriteEndElement(); //customDebugInfo }
public override EditAndContinueMethodDebugInformation GetDebugInfo( MethodDefinitionHandle methodHandle ) { var methodToken = MetadataTokens.GetToken(methodHandle); byte[] debugInfo; try { debugInfo = _symReader.GetCustomDebugInfo(methodToken, _version); } catch (ArgumentOutOfRangeException) { // Sometimes the debugger returns the HRESULT for ArgumentOutOfRangeException, rather than E_FAIL, // for methods without custom debug info (https://github.com/dotnet/roslyn/issues/4138). debugInfo = null; } catch (Exception e) when(FatalError.ReportAndCatch(e)) // likely a bug in the compiler/debugger { throw new InvalidDataException(e.Message, e); } try { ImmutableArray <byte> localSlots, lambdaMap; if (debugInfo != null) { localSlots = CustomDebugInfoReader.TryGetCustomDebugInfoRecord( debugInfo, CustomDebugInfoKind.EditAndContinueLocalSlotMap ); lambdaMap = CustomDebugInfoReader.TryGetCustomDebugInfoRecord( debugInfo, CustomDebugInfoKind.EditAndContinueLambdaMap ); } else { localSlots = lambdaMap = default; } return(EditAndContinueMethodDebugInformation.Create(localSlots, lambdaMap)); } catch (InvalidOperationException e) when(FatalError.ReportAndCatch(e)) // likely a bug in the compiler/debugger { // TODO: CustomDebugInfoReader should throw InvalidDataException throw new InvalidDataException(e.Message, e); } }
/// <exception cref="InvalidOperationException">Bad data.</exception> private static void GetCSharpDynamicLocalInfo( byte[] customDebugInfo, int methodToken, int methodVersion, IEnumerable <ISymUnmanagedScope> scopes, out ImmutableDictionary <int, ImmutableArray <bool> > dynamicLocalMap, out ImmutableDictionary <string, ImmutableArray <bool> > dynamicLocalConstantMap) { dynamicLocalMap = ImmutableDictionary <int, ImmutableArray <bool> > .Empty; dynamicLocalConstantMap = ImmutableDictionary <string, ImmutableArray <bool> > .Empty; var record = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(customDebugInfo, CustomDebugInfoKind.DynamicLocals); if (record.IsDefault) { return; } ImmutableDictionary <int, ImmutableArray <bool> > .Builder localBuilder = null; ImmutableDictionary <string, ImmutableArray <bool> > .Builder constantBuilder = null; var dynamicLocals = RemoveAmbiguousLocals(CustomDebugInfoReader.DecodeDynamicLocalsRecord(record), scopes); foreach (var dynamicLocal in dynamicLocals) { int slot = dynamicLocal.SlotId; var flags = GetFlags(dynamicLocal); if (slot < 0) { constantBuilder = constantBuilder ?? ImmutableDictionary.CreateBuilder <string, ImmutableArray <bool> >(); constantBuilder[dynamicLocal.Name] = flags; } else { localBuilder = localBuilder ?? ImmutableDictionary.CreateBuilder <int, ImmutableArray <bool> >(); localBuilder[slot] = flags; } } if (localBuilder != null) { dynamicLocalMap = localBuilder.ToImmutable(); } if (constantBuilder != null) { dynamicLocalConstantMap = constantBuilder.ToImmutable(); } }
private static void GetTupleElementNamesLocalInfo( byte[] customDebugInfo, out ImmutableDictionary <int, ImmutableArray <string> > tupleLocalMap, out ImmutableDictionary <LocalNameAndScope, ImmutableArray <string> > tupleLocalConstantMap) { tupleLocalMap = null; tupleLocalConstantMap = null; var record = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(customDebugInfo, CustomDebugInfoKind.TupleElementNames); if (record.IsDefault) { return; } ImmutableDictionary <int, ImmutableArray <string> > .Builder localBuilder = null; ImmutableDictionary <LocalNameAndScope, ImmutableArray <string> > .Builder constantBuilder = null; var tuples = CustomDebugInfoReader.DecodeTupleElementNamesRecord(record); foreach (var tuple in tuples) { var slotIndex = tuple.SlotIndex; var elementNames = tuple.ElementNames; if (slotIndex < 0) { constantBuilder = constantBuilder ?? ImmutableDictionary.CreateBuilder <LocalNameAndScope, ImmutableArray <string> >(); var localAndScope = new LocalNameAndScope(tuple.LocalName, tuple.ScopeStart, tuple.ScopeEnd); constantBuilder[localAndScope] = elementNames; } else { localBuilder = localBuilder ?? ImmutableDictionary.CreateBuilder <int, ImmutableArray <string> >(); localBuilder[slotIndex] = elementNames; } } if (localBuilder != null) { tupleLocalMap = localBuilder.ToImmutable(); } if (constantBuilder != null) { tupleLocalConstantMap = constantBuilder.ToImmutable(); } }
public void BadPdb_ForwardChain() { const int methodToken1 = 0x600057a; // Forwards to 2 const int methodToken2 = 0x600055d; // Forwards to 3 const int methodToken3 = 0x6000540; // Has a using const string importString = "USystem"; var getMethodCustomDebugInfo = new Func <int, int, byte[]>((token, _) => { switch (token) { case methodToken1: return(new MethodDebugInfoBytes.Builder().AddForward(methodToken2).Build().Bytes.ToArray()); case methodToken2: return(new MethodDebugInfoBytes.Builder().AddForward(methodToken3).Build().Bytes.ToArray()); case methodToken3: return(new MethodDebugInfoBytes.Builder(new[] { new[] { importString } }).Build().Bytes.ToArray()); default: throw null; } }); var getMethodImportStrings = new Func <int, int, ImmutableArray <string> >((token, _) => { switch (token) { case methodToken3: return(ImmutableArray.Create(importString)); default: throw null; } }); ImmutableArray <string> externAliasStrings; var importStrings = CustomDebugInfoReader.GetCSharpGroupedImportStrings(methodToken1, 0, getMethodCustomDebugInfo, getMethodImportStrings, out externAliasStrings); Assert.True(importStrings.IsDefault); Assert.True(externAliasStrings.IsDefault); importStrings = CustomDebugInfoReader.GetCSharpGroupedImportStrings(methodToken2, 0, getMethodCustomDebugInfo, getMethodImportStrings, out externAliasStrings); Assert.Equal(importString, importStrings.Single().Single()); Assert.Equal(0, externAliasStrings.Length); importStrings = CustomDebugInfoReader.GetCSharpGroupedImportStrings(methodToken2, 0, getMethodCustomDebugInfo, getMethodImportStrings, out externAliasStrings); Assert.Equal(importString, importStrings.Single().Single()); Assert.Equal(0, externAliasStrings.Length); }
public static bool TryCreateFromVisualBasicImportString(string importString, out ImportRecord record, out ImportScope scope) { ImportTargetKind targetKind; string alias; string targetString; if (CustomDebugInfoReader.TryParseVisualBasicImportString(importString, out alias, out targetString, out targetKind, out scope)) { record = new NativeImportRecord( targetKind, externAlias: null, alias: alias, targetString: targetString); return(true); } record = default(ImportRecord); return(false); }
public static bool TryCreateFromCSharpImportString(string importString, out ImportRecord record) { ImportTargetKind targetKind; string externAlias; string alias; string targetString; if (CustomDebugInfoReader.TryParseCSharpImportString(importString, out alias, out externAlias, out targetString, out targetKind)) { record = new NativeImportRecord( targetKind, externAlias, alias, targetString); return(true); } record = default(ImportRecord); return(false); }
private static bool TryParseImportString(string importString, out ImportInfo import, bool vbSemantics) { ImportTargetKind kind; string target; string alias; string externAlias = null; var scope = VBImportScopeKind.Unspecified; if (vbSemantics ? CustomDebugInfoReader.TryParseVisualBasicImportString(importString, out alias, out target, out kind, out scope) : CustomDebugInfoReader.TryParseCSharpImportString(importString, out alias, out externAlias, out target, out kind)) { import = new ImportInfo(kind, target, alias, externAlias, scope); return(true); } // TODO: report warning import = default(ImportInfo); return(false); }
private static bool TryCreateImportRecordFromVisualBasicImportString(string importString, out ImportRecord record, out VBImportScopeKind scope) { ImportTargetKind targetKind; string alias; string targetString; if (CustomDebugInfoReader.TryParseVisualBasicImportString(importString, out alias, out targetString, out targetKind, out scope)) { record = new ImportRecord( targetKind: targetKind, alias: alias, targetType: null, targetString: targetString, targetAssembly: null, targetAssemblyAlias: null); return(true); } record = default(ImportRecord); return(false); }
public void InvalidAlignment2() { // CDIs that don't support alignment: var bytes = new byte[] { 0x04, // version 0x01, // count 0x00, 0x00, 0x04, // version 0x06, // kind 0x00, 0x03, // bad alignment // body size 0x02, 0x00, 0x00, 0x00, // payload 0x01, 0x00, 0x00, 0x06 }; Assert.Throws <InvalidOperationException>(() => CustomDebugInfoReader.GetCustomDebugInfoRecords(bytes).ToArray()); }
public static void Convert(Stream peStream, Stream sourcePdbStream, Stream targetPdbStream) { var metadataBuilder = new MetadataBuilder(); ImmutableArray <int> typeSystemRowCounts; var debugEntryPointToken = default(MethodDefinitionHandle); var pdbId = default(BlobContentId); try { using (var peReader = new PEReader(peStream)) { pdbId = ReadPdbId(peReader); var symReader = SymReaderFactory.CreateWindowsPdbReader(sourcePdbStream, peReader); var metadataReader = peReader.GetMetadataReader(); var metadataModel = new MetadataModel(metadataReader); typeSystemRowCounts = metadataModel.GetRowCounts(); debugEntryPointToken = ReadEntryPointHandle(symReader); // documents: var documentIndex = new Dictionary <string, DocumentHandle>(StringComparer.Ordinal); var documents = symReader.GetDocuments(); metadataBuilder.SetCapacity(TableIndex.Document, documents.Length); bool vbSemantics = false; foreach (var document in documents) { string name = document.GetName(); Guid language = document.GetLanguage(); // TODO: // won't work for IL-merged assmemblies vbSemantics |= language == SymReaderHelpers.VisualBasicLanguageGuid; var rid = metadataBuilder.AddDocument( name: metadataBuilder.GetOrAddDocumentName(name), hashAlgorithm: metadataBuilder.GetOrAddGuid(document.GetHashAlgorithm()), hash: metadataBuilder.GetOrAddBlob(document.GetChecksum()), language: metadataBuilder.GetOrAddGuid(language)); documentIndex.Add(name, rid); } var lastLocalVariableHandle = default(LocalVariableHandle); var lastLocalConstantHandle = default(LocalConstantHandle); var importStringsByMethod = new Dictionary <int, ImmutableArray <string> >(); var importScopesByMethod = new Dictionary <int, ImportScopeHandle>(); // Maps import scope content to import scope handles var importScopeIndex = new Dictionary <ImportScopeInfo, ImportScopeHandle>(); var importScopes = new List <ImportScopeInfo>(); // reserve slot for module import scope: importScopes.Add(default(ImportScopeInfo)); var externAliasImports = new List <ImportInfo>(); var externAliasStringSet = new HashSet <string>(StringComparer.Ordinal); string vbDefaultNamespace = null; var vbProjectLevelImports = new List <ImportInfo>(); // first pass: foreach (var methodHandle in metadataReader.MethodDefinitions) { int methodToken = MetadataTokens.GetToken(methodHandle); ImmutableArray <ImmutableArray <ImportInfo> > importGroups; if (vbSemantics) { var importStrings = CustomDebugInfoReader.GetVisualBasicImportStrings( methodToken, symReader, getMethodImportStrings: (token, sr) => GetImportStrings(token, importStringsByMethod, sr)); if (importStrings.IsEmpty) { // no debug info continue; } var vbFileLevelImports = ArrayBuilder <ImportInfo> .GetInstance(); foreach (var importString in importStrings) { if (TryParseImportString(importString, out var import, vbSemantics: true)) { if (import.Kind == ImportTargetKind.DefaultNamespace) { vbDefaultNamespace = import.Target; } else if (import.Scope == VBImportScopeKind.Project) { vbProjectLevelImports.Add(import); } else { vbFileLevelImports.Add(import); } } } importGroups = ImmutableArray.Create(vbFileLevelImports.ToImmutableAndFree()); } else { var importStringGroups = CustomDebugInfoReader.GetCSharpGroupedImportStrings( methodToken, symReader, getMethodCustomDebugInfo: (token, sr) => sr.GetCustomDebugInfo(token, methodVersion: 1), getMethodImportStrings: (token, sr) => GetImportStrings(token, importStringsByMethod, sr), externAliasStrings: out var localExternAliasStrings); if (importStringGroups.IsDefault) { // no debug info continue; } if (!localExternAliasStrings.IsDefault) { foreach (var externAlias in localExternAliasStrings) { if (externAliasStringSet.Add(externAlias) && TryParseImportString(externAlias, out var import, vbSemantics: false)) { externAliasImports.Add(import); } } } importGroups = ImmutableArray.CreateRange(importStringGroups.Select(g => ParseImportStrings(g, vbSemantics: false))); } var importScopeHandle = DefineImportScope(importGroups, importScopeIndex, importScopes); importScopesByMethod.Add(methodToken, importScopeHandle); } // import scopes: metadataBuilder.AddImportScope( parentScope: default(ImportScopeHandle), imports: SerializeModuleImportScope(metadataBuilder, externAliasImports, vbProjectLevelImports, vbDefaultNamespace, metadataModel)); for (int i = 1; i < importScopes.Count; i++) { metadataBuilder.AddImportScope( parentScope: importScopes[i].Parent, imports: SerializeImportsBlob(metadataBuilder, importScopes[i].Imports, metadataModel)); } var dynamicNames = new Dictionary <string, DynamicLocalInfo>(); var dynamicSlots = new Dictionary <int, DynamicLocalInfo>(); // methods: metadataBuilder.SetCapacity(TableIndex.MethodDebugInformation, metadataReader.MethodDefinitions.Count); foreach (var methodHandle in metadataReader.MethodDefinitions) { var methodDef = metadataReader.GetMethodDefinition(methodHandle); int methodToken = MetadataTokens.GetToken(methodHandle); var symMethod = symReader.GetMethod(methodToken); if (symMethod == null) { metadataBuilder.AddMethodDebugInformation(default(DocumentHandle), sequencePoints: default(BlobHandle)); continue; } // method debug info: int localSignatureRowId; if (methodDef.RelativeVirtualAddress != 0) { var methodBody = peReader.GetMethodBody(methodDef.RelativeVirtualAddress); localSignatureRowId = methodBody.LocalSignature.IsNil ? 0 : MetadataTokens.GetRowNumber(methodBody.LocalSignature); } else { localSignatureRowId = 0; } var symSequencePoints = symMethod.GetSequencePoints().ToImmutableArray(); DocumentHandle singleDocumentHandle; BlobHandle sequencePointsBlob = SerializeSequencePoints(metadataBuilder, localSignatureRowId, symSequencePoints, documentIndex, out singleDocumentHandle); metadataBuilder.AddMethodDebugInformation( document: singleDocumentHandle, sequencePoints: sequencePointsBlob); // state machine and async info: var symAsyncMethod = symMethod.AsAsyncMethod(); if (symAsyncMethod != null) { var kickoffToken = MetadataTokens.Handle(symAsyncMethod.GetKickoffMethod()); metadataBuilder.AddStateMachineMethod( moveNextMethod: methodHandle, kickoffMethod: (MethodDefinitionHandle)kickoffToken); metadataBuilder.AddCustomDebugInformation( parent: methodHandle, kind: metadataBuilder.GetOrAddGuid(PortableCustomDebugInfoKinds.AsyncMethodSteppingInformationBlob), value: SerializeAsyncMethodSteppingInfo(metadataBuilder, symAsyncMethod, MetadataTokens.GetRowNumber(methodHandle))); } // custom debug information: var dynamicLocals = default(ImmutableArray <DynamicLocalInfo>); byte[] customDebugInfoBytes = symReader.GetCustomDebugInfo(methodToken, methodVersion: 1); if (customDebugInfoBytes != null) { foreach (var record in CustomDebugInfoReader.GetCustomDebugInfoRecords(customDebugInfoBytes)) { switch (record.Kind) { case CustomDebugInfoKind.DynamicLocals: dynamicLocals = CustomDebugInfoReader.DecodeDynamicLocalsRecord(record.Data); break; case CustomDebugInfoKind.StateMachineHoistedLocalScopes: metadataBuilder.AddCustomDebugInformation( parent: methodHandle, kind: metadataBuilder.GetOrAddGuid(PortableCustomDebugInfoKinds.EncLocalSlotMap), value: SerializeStateMachineHoistedLocalsBlob(metadataBuilder, CustomDebugInfoReader.DecodeStateMachineHoistedLocalScopesRecord(record.Data))); break; case CustomDebugInfoKind.EditAndContinueLocalSlotMap: metadataBuilder.AddCustomDebugInformation( parent: methodHandle, kind: metadataBuilder.GetOrAddGuid(PortableCustomDebugInfoKinds.EncLocalSlotMap), value: metadataBuilder.GetOrAddBlob(record.Data)); break; case CustomDebugInfoKind.EditAndContinueLambdaMap: metadataBuilder.AddCustomDebugInformation( parent: methodHandle, kind: metadataBuilder.GetOrAddGuid(PortableCustomDebugInfoKinds.EncLambdaAndClosureMap), value: metadataBuilder.GetOrAddBlob(record.Data)); break; } } } var rootScope = symMethod.GetRootScope(); if (rootScope.GetNamespaces().Length == 0 || rootScope.GetLocals().Length == 0 || rootScope.GetConstants().Length == 0) { dynamicNames.Clear(); dynamicSlots.Clear(); foreach (var dynamicLocal in dynamicLocals) { if (dynamicLocal.SlotId == 0) { // All dynamic constants have slot id == 0, // but a variable can also have slot id == 0 if (!dynamicNames.ContainsKey(dynamicLocal.LocalName)) { dynamicNames.Add(dynamicLocal.LocalName, dynamicLocal); } else { // TODO: warning } } else if (!dynamicSlots.ContainsKey(dynamicLocal.SlotId)) { dynamicSlots.Add(dynamicLocal.SlotId, dynamicLocal); } else { // TODO: warning } } foreach (ISymUnmanagedScope scope in rootScope.GetChildren()) { SerializeScope( metadataBuilder, metadataModel, methodHandle, importScopesByMethod[methodToken], scope, dynamicSlots, dynamicNames, vbSemantics, ref lastLocalVariableHandle, ref lastLocalConstantHandle); } } else { // TODO: warning: // "Root scope must be empty (method 0x{0:x8})", MetadataTokens.GetToken(methodHandle)) } } } } catch (COMException e) { // TODO: loc throw new BadImageFormatException("Invalid PDB format: " + e.Message, e); } var serializer = new PortablePdbBuilder(metadataBuilder, typeSystemRowCounts, debugEntryPointToken, idProvider: _ => pdbId); BlobBuilder blobBuilder = new BlobBuilder(); serializer.Serialize(blobBuilder); blobBuilder.WriteContentTo(targetPdbStream); }
public void EncCdiAlignment() { var slots = ImmutableArray.Create( new LocalSlotDebugInfo(SynthesizedLocalKind.UserDefined, new LocalDebugId(-1, 10)), new LocalSlotDebugInfo(SynthesizedLocalKind.TryAwaitPendingCaughtException, new LocalDebugId(-20000, 10))); var closures = ImmutableArray.Create( new ClosureDebugInfo(-100, new DebugId(0, 0)), new ClosureDebugInfo(10, new DebugId(1, 0)), new ClosureDebugInfo(-200, new DebugId(2, 0))); var lambdas = ImmutableArray.Create( new LambdaDebugInfo(20, new DebugId(0, 0), 1), new LambdaDebugInfo(-50, new DebugId(1, 0), 0), new LambdaDebugInfo(-180, new DebugId(2, 0), LambdaDebugInfo.StaticClosureOrdinal)); var debugInfo = new EditAndContinueMethodDebugInformation(1, slots, closures, lambdas); var records = new ArrayBuilder <Cci.PooledBlobBuilder>(); Cci.CustomDebugInfoWriter.SerializeCustomDebugInformation(debugInfo, records); var cdi = Cci.CustomDebugInfoWriter.SerializeCustomDebugMetadata(records); Assert.Equal(2, records.Count); AssertEx.Equal(new byte[] { 0x04, // version 0x06, // record kind 0x00, 0x02, // alignment size // aligned record size 0x18, 0x00, 0x00, 0x00, // payload (4B aligned) 0xFF, 0xC0, 0x00, 0x4E, 0x20, 0x81, 0xC0, 0x00, 0x4E, 0x1F, 0x0A, 0x9A, 0x00, 0x0A, 0x00, 0x00 }, records[0].ToArray()); AssertEx.Equal(new byte[] { 0x04, // version 0x07, // record kind 0x00, 0x00, // alignment size // aligned record size 0x18, 0x00, 0x00, 0x00, // payload (4B aligned) 0x02, 0x80, 0xC8, 0x03, 0x64, 0x80, 0xD2, 0x00, 0x80, 0xDC, 0x03, 0x80, 0x96, 0x02, 0x14, 0x01 }, records[1].ToArray()); var deserialized = CustomDebugInfoReader.GetCustomDebugInfoRecords(cdi).ToArray(); Assert.Equal(CustomDebugInfoKind.EditAndContinueLocalSlotMap, deserialized[0].Kind); Assert.Equal(4, deserialized[0].Version); Assert.Equal(new byte[] { 0xFF, 0xC0, 0x00, 0x4E, 0x20, 0x81, 0xC0, 0x00, 0x4E, 0x1F, 0x0A, 0x9A, 0x00, 0x0A }, deserialized[0].Data); Assert.Equal(CustomDebugInfoKind.EditAndContinueLambdaMap, deserialized[1].Kind); Assert.Equal(4, deserialized[1].Version); Assert.Equal(new byte[] { 0x02, 0x80, 0xC8, 0x03, 0x64, 0x80, 0xD2, 0x00, 0x80, 0xDC, 0x03, 0x80, 0x96, 0x02, 0x14, 0x01 }, deserialized[1].Data); }
public void TryGetCustomDebugInfoRecord1() { byte[] cdi; Assert.Throws <InvalidOperationException>(() => CustomDebugInfoReader.TryGetCustomDebugInfoRecord(new byte[0], CustomDebugInfoKind.EditAndContinueLocalSlotMap)); Assert.Throws <InvalidOperationException>(() => CustomDebugInfoReader.TryGetCustomDebugInfoRecord(new byte[] { 1 }, CustomDebugInfoKind.EditAndContinueLocalSlotMap)); Assert.Throws <InvalidOperationException>(() => CustomDebugInfoReader.TryGetCustomDebugInfoRecord(new byte[] { 1, 2 }, CustomDebugInfoKind.EditAndContinueLocalSlotMap)); // unknown version Assert.True(CustomDebugInfoReader.TryGetCustomDebugInfoRecord(new byte[] { 5, 1, 0, 0 }, CustomDebugInfoKind.EditAndContinueLocalSlotMap).IsDefault); // incomplete record header cdi = new byte[] { 4, 1, 0, 0, // global header 4, (byte)CustomDebugInfoKind.EditAndContinueLocalSlotMap, }; Assert.True(CustomDebugInfoReader.TryGetCustomDebugInfoRecord(cdi, CustomDebugInfoKind.EditAndContinueLocalSlotMap).IsDefault); // record size too small cdi = new byte[] { 4, 1, 0, 0, // global header /*version*/ 4, /*kind*/ (byte)CustomDebugInfoKind.EditAndContinueLocalSlotMap, /*padding*/ 0, 0, /*size:*/ 0, 0, 0, 0, }; Assert.Throws <InvalidOperationException>(() => CustomDebugInfoReader.TryGetCustomDebugInfoRecord(cdi, CustomDebugInfoKind.EditAndContinueLocalSlotMap)); // invalid record size = Int32.MinValue cdi = new byte[] { 4, 1, 0, 0, // global header /*version*/ 4, /*kind*/ (byte)CustomDebugInfoKind.EditAndContinueLocalSlotMap, /*padding*/ 0, 0, /*size:*/ 0x00, 0x00, 0x00, 0x80, 0, 0, 0, 0 }; Assert.Throws <InvalidOperationException>(() => CustomDebugInfoReader.TryGetCustomDebugInfoRecord(cdi, CustomDebugInfoKind.EditAndContinueLocalSlotMap)); // empty record cdi = new byte[] { 4, 1, 0, 0, // global header /*version*/ 4, /*kind*/ (byte)CustomDebugInfoKind.EditAndContinueLocalSlotMap, /*padding*/ 0, 0, /*size:*/ 0x08, 0x00, 0x00, 0x00, }; Assert.True(CustomDebugInfoReader.TryGetCustomDebugInfoRecord(cdi, CustomDebugInfoKind.EditAndContinueLocalSlotMap).IsEmpty); // record size too big cdi = new byte[] { 4, 1, 0, 0, // global header /*version*/ 4, /*kind*/ (byte)CustomDebugInfoKind.EditAndContinueLocalSlotMap, /*padding*/ 0, 0, /*size:*/ 0x0a, 0x00, 0x00, 0x00, 0xab }; Assert.Throws <InvalidOperationException>(() => CustomDebugInfoReader.TryGetCustomDebugInfoRecord(cdi, CustomDebugInfoKind.EditAndContinueLocalSlotMap)); // valid record cdi = new byte[] { 4, 1, 0, 0, // global header /*version*/ 4, /*kind*/ (byte)CustomDebugInfoKind.EditAndContinueLocalSlotMap, /*padding*/ 0, 0, /*size:*/ 0x09, 0x00, 0x00, 0x00, 0xab }; AssertEx.Equal(new byte[] { 0xab }, CustomDebugInfoReader.TryGetCustomDebugInfoRecord(cdi, CustomDebugInfoKind.EditAndContinueLocalSlotMap)); // record not matching cdi = new byte[] { 4, 1, 0, 0, // global header /*version*/ 4, /*kind*/ (byte)CustomDebugInfoKind.DynamicLocals, /*padding*/ 0, 0, /*size:*/ 0x09, 0x00, 0x00, 0x00, 0xab }; Assert.True(CustomDebugInfoReader.TryGetCustomDebugInfoRecord(cdi, CustomDebugInfoKind.EditAndContinueLocalSlotMap).IsDefault); // unknown record kind cdi = new byte[] { 4, 1, 0, 0, // global header /*version*/ 4, /*kind*/ 0xff, /*padding*/ 0, 0, /*size:*/ 0x09, 0x00, 0x00, 0x00, 0xab }; Assert.True(CustomDebugInfoReader.TryGetCustomDebugInfoRecord(cdi, CustomDebugInfoKind.EditAndContinueLocalSlotMap).IsDefault); // multiple records (number in global header is ignored, the first matching record is returned) cdi = new byte[] { 4, 1, 0, 0, // global header /*version*/ 4, /*kind*/ (byte)CustomDebugInfoKind.EditAndContinueLocalSlotMap, /*padding*/ 0, 0, /*size:*/ 0x09, 0x00, 0x00, 0x00, 0xab, /*version*/ 4, /*kind*/ (byte)CustomDebugInfoKind.EditAndContinueLocalSlotMap, /*padding*/ 0, 0, /*size:*/ 0x09, 0x00, 0x00, 0x00, 0xcd }; AssertEx.Equal(new byte[] { 0xab }, CustomDebugInfoReader.TryGetCustomDebugInfoRecord(cdi, CustomDebugInfoKind.EditAndContinueLocalSlotMap)); // multiple records (number in global header is ignored, the first record is returned) cdi = new byte[] { 4, 1, 0, 0, // global header /*version*/ 4, /*kind*/ (byte)CustomDebugInfoKind.DynamicLocals, /*padding*/ 0, 0, /*size:*/ 0x09, 0x00, 0x00, 0x00, 0xab, /*version*/ 4, /*kind*/ (byte)CustomDebugInfoKind.EditAndContinueLocalSlotMap, /*padding*/ 0, 0, /*size:*/ 0x09, 0x00, 0x00, 0x00, 0xcd }; AssertEx.Equal(new byte[] { 0xcd }, CustomDebugInfoReader.TryGetCustomDebugInfoRecord(cdi, CustomDebugInfoKind.EditAndContinueLocalSlotMap)); // multiple records (number in global header is ignored, the first record is returned) cdi = new byte[] { 4, 1, 0, 0, // global header /*version*/ 4, /*kind*/ (byte)CustomDebugInfoKind.DynamicLocals, /*padding*/ 0, 0, /*size:*/ 0x09, 0x00, 0x00, 0x00, 0xab, /*version*/ 4, /*kind*/ (byte)CustomDebugInfoKind.EditAndContinueLocalSlotMap, /*padding*/ 0, 0, /*size:*/ 0x09, 0x00, 0x00, 0x00, 0xcd }; AssertEx.Equal(new byte[] { 0xab }, CustomDebugInfoReader.TryGetCustomDebugInfoRecord(cdi, CustomDebugInfoKind.DynamicLocals)); }
public static MethodDebugInfo GetMethodDebugInfo( this ISymUnmanagedReader reader, int methodToken, int methodVersion) { ImmutableArray <string> externAliasStrings; var importStringGroups = reader.GetCSharpGroupedImportStrings(methodToken, methodVersion, out externAliasStrings); Debug.Assert(importStringGroups.IsDefault == externAliasStrings.IsDefault); if (importStringGroups.IsDefault) { return(default(MethodDebugInfo)); } var importRecordGroupBuilder = ArrayBuilder <ImmutableArray <ImportRecord> > .GetInstance(importStringGroups.Length); foreach (var importStringGroup in importStringGroups) { var groupBuilder = ArrayBuilder <ImportRecord> .GetInstance(importStringGroup.Length); foreach (var importString in importStringGroup) { ImportRecord record; if (NativeImportRecord.TryCreateFromCSharpImportString(importString, out record)) { groupBuilder.Add(record); } else { Debug.WriteLine($"Failed to parse import string {importString}"); } } importRecordGroupBuilder.Add(groupBuilder.ToImmutableAndFree()); } var externAliasRecordBuilder = ArrayBuilder <ExternAliasRecord> .GetInstance(externAliasStrings.Length); foreach (string externAliasString in externAliasStrings) { string alias; string externAlias; string target; ImportTargetKind kind; if (!CustomDebugInfoReader.TryParseCSharpImportString(externAliasString, out alias, out externAlias, out target, out kind)) { Debug.WriteLine($"Unable to parse extern alias '{externAliasString}'"); continue; } Debug.Assert(kind == ImportTargetKind.Assembly, "Programmer error: How did a non-assembly get in the extern alias list?"); Debug.Assert(alias != null); // Name of the extern alias. Debug.Assert(externAlias == null); // Not used. Debug.Assert(target != null); // Name of the target assembly. AssemblyIdentity targetIdentity; if (!AssemblyIdentity.TryParseDisplayName(target, out targetIdentity)) { Debug.WriteLine($"Unable to parse target of extern alias '{externAliasString}'"); continue; } externAliasRecordBuilder.Add(new NativeExternAliasRecord <AssemblySymbol>(alias, targetIdentity)); } return(new MethodDebugInfo( importRecordGroupBuilder.ToImmutableAndFree(), externAliasRecordBuilder.ToImmutableAndFree(), defaultNamespaceName: "")); // Unused in C#. }
public unsafe static MethodDebugInfo <TTypeSymbol, TLocalSymbol> ReadMethodDebugInfo( ISymUnmanagedReader3 symReader, EESymbolProvider <TTypeSymbol, TLocalSymbol> symbolProviderOpt, // TODO: only null in DTEE case where we looking for default namesapace int methodToken, int methodVersion, int ilOffset, bool isVisualBasicMethod) { // no symbols if (symReader == null) { return(None); } if (symReader is ISymUnmanagedReader5 symReader5) { int hr = symReader5.GetPortableDebugMetadataByVersion(methodVersion, out byte *metadata, out int size); ThrowExceptionForHR(hr); if (hr == S_OK) { var mdReader = new MetadataReader(metadata, size); try { return(ReadFromPortable(mdReader, methodToken, ilOffset, symbolProviderOpt, isVisualBasicMethod)); } catch (BadImageFormatException) { // bad CDI, ignore return(None); } } } var allScopes = ArrayBuilder <ISymUnmanagedScope> .GetInstance(); var containingScopes = ArrayBuilder <ISymUnmanagedScope> .GetInstance(); try { var symMethod = symReader.GetMethodByVersion(methodToken, methodVersion); if (symMethod != null) { symMethod.GetAllScopes(allScopes, containingScopes, ilOffset, isScopeEndInclusive: isVisualBasicMethod); } ImmutableArray <ImmutableArray <ImportRecord> > importRecordGroups; ImmutableArray <ExternAliasRecord> externAliasRecords; string defaultNamespaceName; if (isVisualBasicMethod) { ReadVisualBasicImportsDebugInfo( symReader, methodToken, methodVersion, out importRecordGroups, out defaultNamespaceName); externAliasRecords = ImmutableArray <ExternAliasRecord> .Empty; } else { Debug.Assert(symbolProviderOpt != null); ReadCSharpNativeImportsInfo( symReader, symbolProviderOpt, methodToken, methodVersion, out importRecordGroups, out externAliasRecords); defaultNamespaceName = ""; } // VB should read hoisted scope information from local variables: var hoistedLocalScopeRecords = isVisualBasicMethod ? default(ImmutableArray <HoistedLocalScopeRecord>) : ImmutableArray <HoistedLocalScopeRecord> .Empty; ImmutableDictionary <int, ImmutableArray <bool> > dynamicLocalMap = null; ImmutableDictionary <string, ImmutableArray <bool> > dynamicLocalConstantMap = null; ImmutableDictionary <int, ImmutableArray <string> > tupleLocalMap = null; ImmutableDictionary <LocalNameAndScope, ImmutableArray <string> > tupleLocalConstantMap = null; byte[] customDebugInfo = GetCustomDebugInfoBytes(symReader, methodToken, methodVersion); if (customDebugInfo != null) { if (!isVisualBasicMethod) { var customDebugInfoRecord = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(customDebugInfo, CustomDebugInfoKind.StateMachineHoistedLocalScopes); if (!customDebugInfoRecord.IsDefault) { hoistedLocalScopeRecords = CustomDebugInfoReader.DecodeStateMachineHoistedLocalScopesRecord(customDebugInfoRecord) .SelectAsArray(s => new HoistedLocalScopeRecord(s.StartOffset, s.Length)); } GetCSharpDynamicLocalInfo( customDebugInfo, allScopes, out dynamicLocalMap, out dynamicLocalConstantMap); } GetTupleElementNamesLocalInfo( customDebugInfo, out tupleLocalMap, out tupleLocalConstantMap); } var constantsBuilder = ArrayBuilder <TLocalSymbol> .GetInstance(); if (symbolProviderOpt != null) // TODO { GetConstants(constantsBuilder, symbolProviderOpt, containingScopes, dynamicLocalConstantMap, tupleLocalConstantMap); } var reuseSpan = GetReuseSpan(allScopes, ilOffset, isVisualBasicMethod); return(new MethodDebugInfo <TTypeSymbol, TLocalSymbol>( hoistedLocalScopeRecords, importRecordGroups, externAliasRecords, dynamicLocalMap, tupleLocalMap, defaultNamespaceName, containingScopes.GetLocalNames(), constantsBuilder.ToImmutableAndFree(), reuseSpan)); } catch (InvalidOperationException) { // bad CDI, ignore return(None); } finally { allScopes.Free(); containingScopes.Free(); } }
private static void ReadVisualBasicImportsDebugInfo( ISymUnmanagedReader reader, int methodToken, int methodVersion, out ImmutableArray <ImmutableArray <ImportRecord> > importRecordGroups, out string defaultNamespaceName) { importRecordGroups = ImmutableArray <ImmutableArray <ImportRecord> > .Empty; var importStrings = CustomDebugInfoReader.GetVisualBasicImportStrings( methodToken, KeyValuePair.Create(reader, methodVersion), (token, arg) => GetImportStrings(arg.Key, token, arg.Value)); if (importStrings.IsDefault) { defaultNamespaceName = ""; return; } defaultNamespaceName = null; var projectLevelImportRecords = ArrayBuilder <ImportRecord> .GetInstance(); var fileLevelImportRecords = ArrayBuilder <ImportRecord> .GetInstance(); foreach (string importString in importStrings) { Debug.Assert(importString != null); if (importString.Length > 0 && importString[0] == '*') { string alias = null; string target = null; ImportTargetKind kind = 0; VBImportScopeKind scope = 0; if (!CustomDebugInfoReader.TryParseVisualBasicImportString(importString, out alias, out target, out kind, out scope)) { Debug.WriteLine($"Unable to parse import string '{importString}'"); continue; } else if (kind == ImportTargetKind.Defunct) { continue; } Debug.Assert(alias == null); // The default namespace is never aliased. Debug.Assert(target != null); Debug.Assert(kind == ImportTargetKind.DefaultNamespace); // We only expect to see one of these, but it looks like ProcedureContext::LoadImportsAndDefaultNamespaceNormal // implicitly uses the last one if there are multiple. Debug.Assert(defaultNamespaceName == null); defaultNamespaceName = target; } else { ImportRecord importRecord; VBImportScopeKind scope = 0; if (TryCreateImportRecordFromVisualBasicImportString(importString, out importRecord, out scope)) { if (scope == VBImportScopeKind.Project) { projectLevelImportRecords.Add(importRecord); } else { Debug.Assert(scope == VBImportScopeKind.File || scope == VBImportScopeKind.Unspecified); fileLevelImportRecords.Add(importRecord); } } else { Debug.WriteLine($"Failed to parse import string {importString}"); } } } importRecordGroups = ImmutableArray.Create( fileLevelImportRecords.ToImmutableAndFree(), projectLevelImportRecords.ToImmutableAndFree()); defaultNamespaceName = defaultNamespaceName ?? ""; }
/// <exception cref="InvalidOperationException">Bad data.</exception> private static void GetCSharpDynamicLocalInfo( byte[] customDebugInfo, IEnumerable <ISymUnmanagedScope> scopes, out ImmutableDictionary <int, ImmutableArray <bool> > dynamicLocalMap, out ImmutableDictionary <string, ImmutableArray <bool> > dynamicLocalConstantMap) { dynamicLocalMap = null; dynamicLocalConstantMap = null; var record = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(customDebugInfo, CustomDebugInfoKind.DynamicLocals); if (record.IsDefault) { return; } var localKindsByName = PooledDictionary <string, LocalKind> .GetInstance(); GetLocalKindByName(localKindsByName, scopes); ImmutableDictionary <int, ImmutableArray <bool> > .Builder localBuilder = null; ImmutableDictionary <string, ImmutableArray <bool> > .Builder constantBuilder = null; var dynamicLocals = CustomDebugInfoReader.DecodeDynamicLocalsRecord(record); foreach (var dynamicLocal in dynamicLocals) { int slot = dynamicLocal.SlotId; var flags = dynamicLocal.Flags; if (slot == 0) { LocalKind kind; var name = dynamicLocal.LocalName; localKindsByName.TryGetValue(name, out kind); switch (kind) { case LocalKind.DuplicateName: // Drop locals with ambiguous names. continue; case LocalKind.ConstantName: constantBuilder = constantBuilder ?? ImmutableDictionary.CreateBuilder <string, ImmutableArray <bool> >(); constantBuilder[name] = CreateBoolArray(flags); continue; } } localBuilder = localBuilder ?? ImmutableDictionary.CreateBuilder <int, ImmutableArray <bool> >(); localBuilder[slot] = CreateBoolArray(flags); } if (localBuilder != null) { dynamicLocalMap = localBuilder.ToImmutable(); } if (constantBuilder != null) { dynamicLocalConstantMap = constantBuilder.ToImmutable(); } localKindsByName.Free(); }
private static void ReadCSharpNativeImportsInfo( ISymUnmanagedReader3 reader, EESymbolProvider <TTypeSymbol, TLocalSymbol> symbolProvider, int methodToken, int methodVersion, out ImmutableArray <ImmutableArray <ImportRecord> > importRecordGroups, out ImmutableArray <ExternAliasRecord> externAliasRecords) { ImmutableArray <string> externAliasStrings; var importStringGroups = CustomDebugInfoReader.GetCSharpGroupedImportStrings( methodToken, KeyValuePair.Create(reader, methodVersion), getMethodCustomDebugInfo: (token, arg) => GetCustomDebugInfoBytes(arg.Key, token, arg.Value), getMethodImportStrings: (token, arg) => GetImportStrings(arg.Key, token, arg.Value), externAliasStrings: out externAliasStrings); Debug.Assert(importStringGroups.IsDefault == externAliasStrings.IsDefault); ArrayBuilder <ImmutableArray <ImportRecord> > importRecordGroupBuilder = null; ArrayBuilder <ExternAliasRecord> externAliasRecordBuilder = null; if (!importStringGroups.IsDefault) { importRecordGroupBuilder = ArrayBuilder <ImmutableArray <ImportRecord> > .GetInstance(importStringGroups.Length); foreach (var importStringGroup in importStringGroups) { var groupBuilder = ArrayBuilder <ImportRecord> .GetInstance(importStringGroup.Length); foreach (var importString in importStringGroup) { ImportRecord record; if (TryCreateImportRecordFromCSharpImportString(symbolProvider, importString, out record)) { groupBuilder.Add(record); } else { Debug.WriteLine($"Failed to parse import string {importString}"); } } importRecordGroupBuilder.Add(groupBuilder.ToImmutableAndFree()); } if (!externAliasStrings.IsDefault) { externAliasRecordBuilder = ArrayBuilder <ExternAliasRecord> .GetInstance(externAliasStrings.Length); foreach (string externAliasString in externAliasStrings) { string alias; string externAlias; string target; ImportTargetKind kind; if (!CustomDebugInfoReader.TryParseCSharpImportString(externAliasString, out alias, out externAlias, out target, out kind)) { Debug.WriteLine($"Unable to parse extern alias '{externAliasString}'"); continue; } Debug.Assert(kind == ImportTargetKind.Assembly, "Programmer error: How did a non-assembly get in the extern alias list?"); Debug.Assert(alias != null); // Name of the extern alias. Debug.Assert(externAlias == null); // Not used. Debug.Assert(target != null); // Name of the target assembly. AssemblyIdentity targetIdentity; if (!AssemblyIdentity.TryParseDisplayName(target, out targetIdentity)) { Debug.WriteLine($"Unable to parse target of extern alias '{externAliasString}'"); continue; } externAliasRecordBuilder.Add(new ExternAliasRecord(alias, targetIdentity)); } } } importRecordGroups = importRecordGroupBuilder?.ToImmutableAndFree() ?? ImmutableArray <ImmutableArray <ImportRecord> > .Empty; externAliasRecords = externAliasRecordBuilder?.ToImmutableAndFree() ?? ImmutableArray <ExternAliasRecord> .Empty; }
public static MethodDebugInfo GetMethodDebugInfo( this ISymUnmanagedReader reader, int methodToken, int methodVersion, ArrayBuilder <ISymUnmanagedScope> scopes) { ImmutableArray <string> externAliasStrings; var importStringGroups = reader.GetCSharpGroupedImportStrings(methodToken, methodVersion, out externAliasStrings); Debug.Assert(importStringGroups.IsDefault == externAliasStrings.IsDefault); ArrayBuilder <ImmutableArray <ImportRecord> > importRecordGroupBuilder = null; ArrayBuilder <ExternAliasRecord> externAliasRecordBuilder = null; if (!importStringGroups.IsDefault) { importRecordGroupBuilder = ArrayBuilder <ImmutableArray <ImportRecord> > .GetInstance(importStringGroups.Length); foreach (var importStringGroup in importStringGroups) { var groupBuilder = ArrayBuilder <ImportRecord> .GetInstance(importStringGroup.Length); foreach (var importString in importStringGroup) { ImportRecord record; if (NativeImportRecord.TryCreateFromCSharpImportString(importString, out record)) { groupBuilder.Add(record); } else { Debug.WriteLine($"Failed to parse import string {importString}"); } } importRecordGroupBuilder.Add(groupBuilder.ToImmutableAndFree()); } if (!externAliasStrings.IsDefault) { externAliasRecordBuilder = ArrayBuilder <ExternAliasRecord> .GetInstance(externAliasStrings.Length); foreach (string externAliasString in externAliasStrings) { string alias; string externAlias; string target; ImportTargetKind kind; if (!CustomDebugInfoReader.TryParseCSharpImportString(externAliasString, out alias, out externAlias, out target, out kind)) { Debug.WriteLine($"Unable to parse extern alias '{externAliasString}'"); continue; } Debug.Assert(kind == ImportTargetKind.Assembly, "Programmer error: How did a non-assembly get in the extern alias list?"); Debug.Assert(alias != null); // Name of the extern alias. Debug.Assert(externAlias == null); // Not used. Debug.Assert(target != null); // Name of the target assembly. AssemblyIdentity targetIdentity; if (!AssemblyIdentity.TryParseDisplayName(target, out targetIdentity)) { Debug.WriteLine($"Unable to parse target of extern alias '{externAliasString}'"); continue; } externAliasRecordBuilder.Add(new NativeExternAliasRecord <AssemblySymbol>(alias, targetIdentity)); } } } var hoistedLocalScopeRecords = ImmutableArray <HoistedLocalScopeRecord> .Empty; var dynamicLocalMap = ImmutableDictionary <int, ImmutableArray <bool> > .Empty; var dynamicLocalConstantMap = ImmutableDictionary <string, ImmutableArray <bool> > .Empty; byte[] customDebugInfoBytes = reader.GetCustomDebugInfoBytes(methodToken, methodVersion); if (customDebugInfoBytes != null) { var customDebugInfoRecord = CustomDebugInfoReader.TryGetCustomDebugInfoRecord(customDebugInfoBytes, CustomDebugInfoKind.StateMachineHoistedLocalScopes); if (!customDebugInfoRecord.IsDefault) { hoistedLocalScopeRecords = CustomDebugInfoReader.DecodeStateMachineHoistedLocalScopesRecord(customDebugInfoRecord) .SelectAsArray(s => HoistedLocalScopeRecord.FromNative(s.StartOffset, s.EndOffset)); } CustomDebugInfoReader.GetCSharpDynamicLocalInfo( customDebugInfoBytes, methodToken, methodVersion, scopes, out dynamicLocalMap, out dynamicLocalConstantMap); } return(new MethodDebugInfo( hoistedLocalScopeRecords, importRecordGroupBuilder?.ToImmutableAndFree() ?? ImmutableArray <ImmutableArray <ImportRecord> > .Empty, externAliasRecordBuilder?.ToImmutableAndFree() ?? ImmutableArray <ExternAliasRecord> .Empty, dynamicLocalMap, dynamicLocalConstantMap, defaultNamespaceName: "")); // Unused in C#. }
/// <summary> /// Create a context for evaluating expressions within a method scope. /// </summary> /// <param name="previous">Previous context, if any, for possible re-use.</param> /// <param name="metadataBlocks">Module metadata</param> /// <param name="symReader"><see cref="ISymUnmanagedReader"/> for PDB associated with <paramref name="moduleVersionId"/></param> /// <param name="moduleVersionId">Module containing method</param> /// <param name="methodToken">Method metadata token</param> /// <param name="methodVersion">Method version.</param> /// <param name="ilOffset">IL offset of instruction pointer in method</param> /// <param name="localSignatureToken">Method local signature token</param> /// <returns>Evaluation context</returns> internal static EvaluationContext CreateMethodContext( CSharpMetadataContext previous, ImmutableArray <MetadataBlock> metadataBlocks, object symReader, Guid moduleVersionId, int methodToken, int methodVersion, int ilOffset, int localSignatureToken) { Debug.Assert(MetadataTokens.Handle(methodToken).Kind == HandleKind.MethodDefinition); var typedSymReader = (ISymUnmanagedReader)symReader; var scopes = ArrayBuilder <ISymUnmanagedScope> .GetInstance(); typedSymReader.GetScopes(methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive, scopes); var scope = scopes.GetMethodScope(methodToken, methodVersion); // Re-use the previous compilation if possible. CSharpCompilation compilation; if (metadataBlocks.HaveNotChanged(previous)) { // Re-use entire context if method scope has not changed. var previousContext = previous.EvaluationContext; if ((scope != null) && (previousContext != null) && scope.Equals(previousContext.MethodScope)) { return(previousContext); } compilation = previous.Compilation; } else { compilation = metadataBlocks.ToCompilation(); } var localNames = scopes.GetLocalNames(); var dynamicLocalMap = ImmutableDictionary <int, ImmutableArray <bool> > .Empty; var dynamicLocalConstantMap = ImmutableDictionary <string, ImmutableArray <bool> > .Empty; var inScopeHoistedLocalIndices = ImmutableSortedSet <int> .Empty; var methodDebugInfo = default(MethodDebugInfo); if (typedSymReader != null) { try { var cdi = typedSymReader.GetCustomDebugInfoBytes(methodToken, methodVersion); if (cdi != null) { CustomDebugInfoReader.GetCSharpDynamicLocalInfo( cdi, methodToken, methodVersion, localNames.FirstOrDefault(), out dynamicLocalMap, out dynamicLocalConstantMap); inScopeHoistedLocalIndices = CustomDebugInfoReader.GetCSharpInScopeHoistedLocalIndices( cdi, methodToken, methodVersion, ilOffset); } // TODO (acasey): switch on the type of typedSymReader and call the appropriate helper. (GH #702) methodDebugInfo = typedSymReader.GetMethodDebugInfo(methodToken, methodVersion); } catch (InvalidOperationException) { // bad CDI, ignore } } var methodHandle = (MethodDefinitionHandle)MetadataTokens.Handle(methodToken); var currentFrame = compilation.GetMethod(moduleVersionId, methodHandle); Debug.Assert((object)currentFrame != null); var metadataDecoder = new MetadataDecoder((PEModuleSymbol)currentFrame.ContainingModule, currentFrame); var localInfo = metadataDecoder.GetLocalInfo(localSignatureToken); var localBuilder = ArrayBuilder <LocalSymbol> .GetInstance(); var sourceAssembly = compilation.SourceAssembly; GetLocals(localBuilder, currentFrame, localNames, localInfo, dynamicLocalMap, sourceAssembly); GetConstants(localBuilder, currentFrame, scopes.GetConstantSignatures(), metadataDecoder, dynamicLocalConstantMap, sourceAssembly); scopes.Free(); var locals = localBuilder.ToImmutableAndFree(); return(new EvaluationContext( metadataBlocks, scope, compilation, metadataDecoder, currentFrame, locals, inScopeHoistedLocalIndices, methodDebugInfo)); }